alpar@1
|
1 |
/* glpipm.c */
|
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 "glpipm.h"
|
alpar@1
|
26 |
#include "glpmat.h"
|
alpar@1
|
27 |
|
alpar@1
|
28 |
#define ITER_MAX 100
|
alpar@1
|
29 |
/* maximal number of iterations */
|
alpar@1
|
30 |
|
alpar@1
|
31 |
struct csa
|
alpar@1
|
32 |
{ /* common storage area */
|
alpar@1
|
33 |
/*--------------------------------------------------------------*/
|
alpar@1
|
34 |
/* LP data */
|
alpar@1
|
35 |
int m;
|
alpar@1
|
36 |
/* number of rows (equality constraints) */
|
alpar@1
|
37 |
int n;
|
alpar@1
|
38 |
/* number of columns (structural variables) */
|
alpar@1
|
39 |
int *A_ptr; /* int A_ptr[1+m+1]; */
|
alpar@1
|
40 |
int *A_ind; /* int A_ind[A_ptr[m+1]]; */
|
alpar@1
|
41 |
double *A_val; /* double A_val[A_ptr[m+1]]; */
|
alpar@1
|
42 |
/* mxn-matrix A in storage-by-rows format */
|
alpar@1
|
43 |
double *b; /* double b[1+m]; */
|
alpar@1
|
44 |
/* m-vector b of right-hand sides */
|
alpar@1
|
45 |
double *c; /* double c[1+n]; */
|
alpar@1
|
46 |
/* n-vector c of objective coefficients; c[0] is constant term of
|
alpar@1
|
47 |
the objective function */
|
alpar@1
|
48 |
/*--------------------------------------------------------------*/
|
alpar@1
|
49 |
/* LP solution */
|
alpar@1
|
50 |
double *x; /* double x[1+n]; */
|
alpar@1
|
51 |
double *y; /* double y[1+m]; */
|
alpar@1
|
52 |
double *z; /* double z[1+n]; */
|
alpar@1
|
53 |
/* current point in primal-dual space; the best point on exit */
|
alpar@1
|
54 |
/*--------------------------------------------------------------*/
|
alpar@1
|
55 |
/* control parameters */
|
alpar@1
|
56 |
const glp_iptcp *parm;
|
alpar@1
|
57 |
/*--------------------------------------------------------------*/
|
alpar@1
|
58 |
/* working arrays and variables */
|
alpar@1
|
59 |
double *D; /* double D[1+n]; */
|
alpar@1
|
60 |
/* diagonal nxn-matrix D = X*inv(Z), where X = diag(x[j]) and
|
alpar@1
|
61 |
Z = diag(z[j]) */
|
alpar@1
|
62 |
int *P; /* int P[1+m+m]; */
|
alpar@1
|
63 |
/* permutation mxm-matrix P used to minimize fill-in in Cholesky
|
alpar@1
|
64 |
factorization */
|
alpar@1
|
65 |
int *S_ptr; /* int S_ptr[1+m+1]; */
|
alpar@1
|
66 |
int *S_ind; /* int S_ind[S_ptr[m+1]]; */
|
alpar@1
|
67 |
double *S_val; /* double S_val[S_ptr[m+1]]; */
|
alpar@1
|
68 |
double *S_diag; /* double S_diag[1+m]; */
|
alpar@1
|
69 |
/* symmetric mxm-matrix S = P*A*D*A'*P' whose upper triangular
|
alpar@1
|
70 |
part without diagonal elements is stored in S_ptr, S_ind, and
|
alpar@1
|
71 |
S_val in storage-by-rows format, diagonal elements are stored
|
alpar@1
|
72 |
in S_diag */
|
alpar@1
|
73 |
int *U_ptr; /* int U_ptr[1+m+1]; */
|
alpar@1
|
74 |
int *U_ind; /* int U_ind[U_ptr[m+1]]; */
|
alpar@1
|
75 |
double *U_val; /* double U_val[U_ptr[m+1]]; */
|
alpar@1
|
76 |
double *U_diag; /* double U_diag[1+m]; */
|
alpar@1
|
77 |
/* upper triangular mxm-matrix U defining Cholesky factorization
|
alpar@1
|
78 |
S = U'*U; its non-diagonal elements are stored in U_ptr, U_ind,
|
alpar@1
|
79 |
U_val in storage-by-rows format, diagonal elements are stored
|
alpar@1
|
80 |
in U_diag */
|
alpar@1
|
81 |
int iter;
|
alpar@1
|
82 |
/* iteration number (0, 1, 2, ...); iter = 0 corresponds to the
|
alpar@1
|
83 |
initial point */
|
alpar@1
|
84 |
double obj;
|
alpar@1
|
85 |
/* current value of the objective function */
|
alpar@1
|
86 |
double rpi;
|
alpar@1
|
87 |
/* relative primal infeasibility rpi = ||A*x-b||/(1+||b||) */
|
alpar@1
|
88 |
double rdi;
|
alpar@1
|
89 |
/* relative dual infeasibility rdi = ||A'*y+z-c||/(1+||c||) */
|
alpar@1
|
90 |
double gap;
|
alpar@1
|
91 |
/* primal-dual gap = |c'*x-b'*y|/(1+|c'*x|) which is a relative
|
alpar@1
|
92 |
difference between primal and dual objective functions */
|
alpar@1
|
93 |
double phi;
|
alpar@1
|
94 |
/* merit function phi = ||A*x-b||/max(1,||b||) +
|
alpar@1
|
95 |
+ ||A'*y+z-c||/max(1,||c||) +
|
alpar@1
|
96 |
+ |c'*x-b'*y|/max(1,||b||,||c||) */
|
alpar@1
|
97 |
double mu;
|
alpar@1
|
98 |
/* duality measure mu = x'*z/n (used as barrier parameter) */
|
alpar@1
|
99 |
double rmu;
|
alpar@1
|
100 |
/* rmu = max(||A*x-b||,||A'*y+z-c||)/mu */
|
alpar@1
|
101 |
double rmu0;
|
alpar@1
|
102 |
/* the initial value of rmu on iteration 0 */
|
alpar@1
|
103 |
double *phi_min; /* double phi_min[1+ITER_MAX]; */
|
alpar@1
|
104 |
/* phi_min[k] = min(phi[k]), where phi[k] is the value of phi on
|
alpar@1
|
105 |
k-th iteration, 0 <= k <= iter */
|
alpar@1
|
106 |
int best_iter;
|
alpar@1
|
107 |
/* iteration number, on which the value of phi reached its best
|
alpar@1
|
108 |
(minimal) value */
|
alpar@1
|
109 |
double *best_x; /* double best_x[1+n]; */
|
alpar@1
|
110 |
double *best_y; /* double best_y[1+m]; */
|
alpar@1
|
111 |
double *best_z; /* double best_z[1+n]; */
|
alpar@1
|
112 |
/* best point (in the sense of the merit function phi) which has
|
alpar@1
|
113 |
been reached on iteration iter_best */
|
alpar@1
|
114 |
double best_obj;
|
alpar@1
|
115 |
/* objective value at the best point */
|
alpar@1
|
116 |
double *dx_aff; /* double dx_aff[1+n]; */
|
alpar@1
|
117 |
double *dy_aff; /* double dy_aff[1+m]; */
|
alpar@1
|
118 |
double *dz_aff; /* double dz_aff[1+n]; */
|
alpar@1
|
119 |
/* affine scaling direction */
|
alpar@1
|
120 |
double alfa_aff_p, alfa_aff_d;
|
alpar@1
|
121 |
/* maximal primal and dual stepsizes in affine scaling direction,
|
alpar@1
|
122 |
on which x and z are still non-negative */
|
alpar@1
|
123 |
double mu_aff;
|
alpar@1
|
124 |
/* duality measure mu_aff = x_aff'*z_aff/n in the boundary point
|
alpar@1
|
125 |
x_aff' = x+alfa_aff_p*dx_aff, z_aff' = z+alfa_aff_d*dz_aff */
|
alpar@1
|
126 |
double sigma;
|
alpar@1
|
127 |
/* Mehrotra's heuristic parameter (0 <= sigma <= 1) */
|
alpar@1
|
128 |
double *dx_cc; /* double dx_cc[1+n]; */
|
alpar@1
|
129 |
double *dy_cc; /* double dy_cc[1+m]; */
|
alpar@1
|
130 |
double *dz_cc; /* double dz_cc[1+n]; */
|
alpar@1
|
131 |
/* centering corrector direction */
|
alpar@1
|
132 |
double *dx; /* double dx[1+n]; */
|
alpar@1
|
133 |
double *dy; /* double dy[1+m]; */
|
alpar@1
|
134 |
double *dz; /* double dz[1+n]; */
|
alpar@1
|
135 |
/* final combined direction dx = dx_aff+dx_cc, dy = dy_aff+dy_cc,
|
alpar@1
|
136 |
dz = dz_aff+dz_cc */
|
alpar@1
|
137 |
double alfa_max_p;
|
alpar@1
|
138 |
double alfa_max_d;
|
alpar@1
|
139 |
/* maximal primal and dual stepsizes in combined direction, on
|
alpar@1
|
140 |
which x and z are still non-negative */
|
alpar@1
|
141 |
};
|
alpar@1
|
142 |
|
alpar@1
|
143 |
/***********************************************************************
|
alpar@1
|
144 |
* initialize - allocate and initialize common storage area
|
alpar@1
|
145 |
*
|
alpar@1
|
146 |
* This routine allocates and initializes the common storage area (CSA)
|
alpar@1
|
147 |
* used by interior-point method routines. */
|
alpar@1
|
148 |
|
alpar@1
|
149 |
static void initialize(struct csa *csa)
|
alpar@1
|
150 |
{ int m = csa->m;
|
alpar@1
|
151 |
int n = csa->n;
|
alpar@1
|
152 |
int i;
|
alpar@1
|
153 |
if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
154 |
xprintf("Matrix A has %d non-zeros\n", csa->A_ptr[m+1]-1);
|
alpar@1
|
155 |
csa->D = xcalloc(1+n, sizeof(double));
|
alpar@1
|
156 |
/* P := I */
|
alpar@1
|
157 |
csa->P = xcalloc(1+m+m, sizeof(int));
|
alpar@1
|
158 |
for (i = 1; i <= m; i++) csa->P[i] = csa->P[m+i] = i;
|
alpar@1
|
159 |
/* S := A*A', symbolically */
|
alpar@1
|
160 |
csa->S_ptr = xcalloc(1+m+1, sizeof(int));
|
alpar@1
|
161 |
csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind,
|
alpar@1
|
162 |
csa->S_ptr);
|
alpar@1
|
163 |
if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
164 |
xprintf("Matrix S = A*A' has %d non-zeros (upper triangle)\n",
|
alpar@1
|
165 |
csa->S_ptr[m+1]-1 + m);
|
alpar@1
|
166 |
/* determine P using specified ordering algorithm */
|
alpar@1
|
167 |
if (csa->parm->ord_alg == GLP_ORD_NONE)
|
alpar@1
|
168 |
{ if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
169 |
xprintf("Original ordering is being used\n");
|
alpar@1
|
170 |
for (i = 1; i <= m; i++)
|
alpar@1
|
171 |
csa->P[i] = csa->P[m+i] = i;
|
alpar@1
|
172 |
}
|
alpar@1
|
173 |
else if (csa->parm->ord_alg == GLP_ORD_QMD)
|
alpar@1
|
174 |
{ if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
175 |
xprintf("Minimum degree ordering (QMD)...\n");
|
alpar@1
|
176 |
min_degree(m, csa->S_ptr, csa->S_ind, csa->P);
|
alpar@1
|
177 |
}
|
alpar@1
|
178 |
else if (csa->parm->ord_alg == GLP_ORD_AMD)
|
alpar@1
|
179 |
{ if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
180 |
xprintf("Approximate minimum degree ordering (AMD)...\n");
|
alpar@1
|
181 |
amd_order1(m, csa->S_ptr, csa->S_ind, csa->P);
|
alpar@1
|
182 |
}
|
alpar@1
|
183 |
else if (csa->parm->ord_alg == GLP_ORD_SYMAMD)
|
alpar@1
|
184 |
{ if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
185 |
xprintf("Approximate minimum degree ordering (SYMAMD)...\n")
|
alpar@1
|
186 |
;
|
alpar@1
|
187 |
symamd_ord(m, csa->S_ptr, csa->S_ind, csa->P);
|
alpar@1
|
188 |
}
|
alpar@1
|
189 |
else
|
alpar@1
|
190 |
xassert(csa != csa);
|
alpar@1
|
191 |
/* S := P*A*A'*P', symbolically */
|
alpar@1
|
192 |
xfree(csa->S_ind);
|
alpar@1
|
193 |
csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind,
|
alpar@1
|
194 |
csa->S_ptr);
|
alpar@1
|
195 |
csa->S_val = xcalloc(csa->S_ptr[m+1], sizeof(double));
|
alpar@1
|
196 |
csa->S_diag = xcalloc(1+m, sizeof(double));
|
alpar@1
|
197 |
/* compute Cholesky factorization S = U'*U, symbolically */
|
alpar@1
|
198 |
if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
199 |
xprintf("Computing Cholesky factorization S = L*L'...\n");
|
alpar@1
|
200 |
csa->U_ptr = xcalloc(1+m+1, sizeof(int));
|
alpar@1
|
201 |
csa->U_ind = chol_symbolic(m, csa->S_ptr, csa->S_ind, csa->U_ptr);
|
alpar@1
|
202 |
if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
203 |
xprintf("Matrix L has %d non-zeros\n", csa->U_ptr[m+1]-1 + m);
|
alpar@1
|
204 |
csa->U_val = xcalloc(csa->U_ptr[m+1], sizeof(double));
|
alpar@1
|
205 |
csa->U_diag = xcalloc(1+m, sizeof(double));
|
alpar@1
|
206 |
csa->iter = 0;
|
alpar@1
|
207 |
csa->obj = 0.0;
|
alpar@1
|
208 |
csa->rpi = 0.0;
|
alpar@1
|
209 |
csa->rdi = 0.0;
|
alpar@1
|
210 |
csa->gap = 0.0;
|
alpar@1
|
211 |
csa->phi = 0.0;
|
alpar@1
|
212 |
csa->mu = 0.0;
|
alpar@1
|
213 |
csa->rmu = 0.0;
|
alpar@1
|
214 |
csa->rmu0 = 0.0;
|
alpar@1
|
215 |
csa->phi_min = xcalloc(1+ITER_MAX, sizeof(double));
|
alpar@1
|
216 |
csa->best_iter = 0;
|
alpar@1
|
217 |
csa->best_x = xcalloc(1+n, sizeof(double));
|
alpar@1
|
218 |
csa->best_y = xcalloc(1+m, sizeof(double));
|
alpar@1
|
219 |
csa->best_z = xcalloc(1+n, sizeof(double));
|
alpar@1
|
220 |
csa->best_obj = 0.0;
|
alpar@1
|
221 |
csa->dx_aff = xcalloc(1+n, sizeof(double));
|
alpar@1
|
222 |
csa->dy_aff = xcalloc(1+m, sizeof(double));
|
alpar@1
|
223 |
csa->dz_aff = xcalloc(1+n, sizeof(double));
|
alpar@1
|
224 |
csa->alfa_aff_p = 0.0;
|
alpar@1
|
225 |
csa->alfa_aff_d = 0.0;
|
alpar@1
|
226 |
csa->mu_aff = 0.0;
|
alpar@1
|
227 |
csa->sigma = 0.0;
|
alpar@1
|
228 |
csa->dx_cc = xcalloc(1+n, sizeof(double));
|
alpar@1
|
229 |
csa->dy_cc = xcalloc(1+m, sizeof(double));
|
alpar@1
|
230 |
csa->dz_cc = xcalloc(1+n, sizeof(double));
|
alpar@1
|
231 |
csa->dx = csa->dx_aff;
|
alpar@1
|
232 |
csa->dy = csa->dy_aff;
|
alpar@1
|
233 |
csa->dz = csa->dz_aff;
|
alpar@1
|
234 |
csa->alfa_max_p = 0.0;
|
alpar@1
|
235 |
csa->alfa_max_d = 0.0;
|
alpar@1
|
236 |
return;
|
alpar@1
|
237 |
}
|
alpar@1
|
238 |
|
alpar@1
|
239 |
/***********************************************************************
|
alpar@1
|
240 |
* A_by_vec - compute y = A*x
|
alpar@1
|
241 |
*
|
alpar@1
|
242 |
* This routine computes matrix-vector product y = A*x, where A is the
|
alpar@1
|
243 |
* constraint matrix. */
|
alpar@1
|
244 |
|
alpar@1
|
245 |
static void A_by_vec(struct csa *csa, double x[], double y[])
|
alpar@1
|
246 |
{ /* compute y = A*x */
|
alpar@1
|
247 |
int m = csa->m;
|
alpar@1
|
248 |
int *A_ptr = csa->A_ptr;
|
alpar@1
|
249 |
int *A_ind = csa->A_ind;
|
alpar@1
|
250 |
double *A_val = csa->A_val;
|
alpar@1
|
251 |
int i, t, beg, end;
|
alpar@1
|
252 |
double temp;
|
alpar@1
|
253 |
for (i = 1; i <= m; i++)
|
alpar@1
|
254 |
{ temp = 0.0;
|
alpar@1
|
255 |
beg = A_ptr[i], end = A_ptr[i+1];
|
alpar@1
|
256 |
for (t = beg; t < end; t++) temp += A_val[t] * x[A_ind[t]];
|
alpar@1
|
257 |
y[i] = temp;
|
alpar@1
|
258 |
}
|
alpar@1
|
259 |
return;
|
alpar@1
|
260 |
}
|
alpar@1
|
261 |
|
alpar@1
|
262 |
/***********************************************************************
|
alpar@1
|
263 |
* AT_by_vec - compute y = A'*x
|
alpar@1
|
264 |
*
|
alpar@1
|
265 |
* This routine computes matrix-vector product y = A'*x, where A' is a
|
alpar@1
|
266 |
* matrix transposed to the constraint matrix A. */
|
alpar@1
|
267 |
|
alpar@1
|
268 |
static void AT_by_vec(struct csa *csa, double x[], double y[])
|
alpar@1
|
269 |
{ /* compute y = A'*x, where A' is transposed to A */
|
alpar@1
|
270 |
int m = csa->m;
|
alpar@1
|
271 |
int n = csa->n;
|
alpar@1
|
272 |
int *A_ptr = csa->A_ptr;
|
alpar@1
|
273 |
int *A_ind = csa->A_ind;
|
alpar@1
|
274 |
double *A_val = csa->A_val;
|
alpar@1
|
275 |
int i, j, t, beg, end;
|
alpar@1
|
276 |
double temp;
|
alpar@1
|
277 |
for (j = 1; j <= n; j++) y[j] = 0.0;
|
alpar@1
|
278 |
for (i = 1; i <= m; i++)
|
alpar@1
|
279 |
{ temp = x[i];
|
alpar@1
|
280 |
if (temp == 0.0) continue;
|
alpar@1
|
281 |
beg = A_ptr[i], end = A_ptr[i+1];
|
alpar@1
|
282 |
for (t = beg; t < end; t++) y[A_ind[t]] += A_val[t] * temp;
|
alpar@1
|
283 |
}
|
alpar@1
|
284 |
return;
|
alpar@1
|
285 |
}
|
alpar@1
|
286 |
|
alpar@1
|
287 |
/***********************************************************************
|
alpar@1
|
288 |
* decomp_NE - numeric factorization of matrix S = P*A*D*A'*P'
|
alpar@1
|
289 |
*
|
alpar@1
|
290 |
* This routine implements numeric phase of Cholesky factorization of
|
alpar@1
|
291 |
* the matrix S = P*A*D*A'*P', which is a permuted matrix of the normal
|
alpar@1
|
292 |
* equation system. Matrix D is assumed to be already computed. */
|
alpar@1
|
293 |
|
alpar@1
|
294 |
static void decomp_NE(struct csa *csa)
|
alpar@1
|
295 |
{ adat_numeric(csa->m, csa->n, csa->P, csa->A_ptr, csa->A_ind,
|
alpar@1
|
296 |
csa->A_val, csa->D, csa->S_ptr, csa->S_ind, csa->S_val,
|
alpar@1
|
297 |
csa->S_diag);
|
alpar@1
|
298 |
chol_numeric(csa->m, csa->S_ptr, csa->S_ind, csa->S_val,
|
alpar@1
|
299 |
csa->S_diag, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag);
|
alpar@1
|
300 |
return;
|
alpar@1
|
301 |
}
|
alpar@1
|
302 |
|
alpar@1
|
303 |
/***********************************************************************
|
alpar@1
|
304 |
* solve_NE - solve normal equation system
|
alpar@1
|
305 |
*
|
alpar@1
|
306 |
* This routine solves the normal equation system:
|
alpar@1
|
307 |
*
|
alpar@1
|
308 |
* A*D*A'*y = h.
|
alpar@1
|
309 |
*
|
alpar@1
|
310 |
* It is assumed that the matrix A*D*A' has been previously factorized
|
alpar@1
|
311 |
* by the routine decomp_NE.
|
alpar@1
|
312 |
*
|
alpar@1
|
313 |
* On entry the array y contains the vector of right-hand sides h. On
|
alpar@1
|
314 |
* exit this array contains the computed vector of unknowns y.
|
alpar@1
|
315 |
*
|
alpar@1
|
316 |
* Once the vector y has been computed the routine checks for numeric
|
alpar@1
|
317 |
* stability. If the residual vector:
|
alpar@1
|
318 |
*
|
alpar@1
|
319 |
* r = A*D*A'*y - h
|
alpar@1
|
320 |
*
|
alpar@1
|
321 |
* is relatively small, the routine returns zero, otherwise non-zero is
|
alpar@1
|
322 |
* returned. */
|
alpar@1
|
323 |
|
alpar@1
|
324 |
static int solve_NE(struct csa *csa, double y[])
|
alpar@1
|
325 |
{ int m = csa->m;
|
alpar@1
|
326 |
int n = csa->n;
|
alpar@1
|
327 |
int *P = csa->P;
|
alpar@1
|
328 |
int i, j, ret = 0;
|
alpar@1
|
329 |
double *h, *r, *w;
|
alpar@1
|
330 |
/* save vector of right-hand sides h */
|
alpar@1
|
331 |
h = xcalloc(1+m, sizeof(double));
|
alpar@1
|
332 |
for (i = 1; i <= m; i++) h[i] = y[i];
|
alpar@1
|
333 |
/* solve normal equation system (A*D*A')*y = h */
|
alpar@1
|
334 |
/* since S = P*A*D*A'*P' = U'*U, then A*D*A' = P'*U'*U*P, so we
|
alpar@1
|
335 |
have inv(A*D*A') = P'*inv(U)*inv(U')*P */
|
alpar@1
|
336 |
/* w := P*h */
|
alpar@1
|
337 |
w = xcalloc(1+m, sizeof(double));
|
alpar@1
|
338 |
for (i = 1; i <= m; i++) w[i] = y[P[i]];
|
alpar@1
|
339 |
/* w := inv(U')*w */
|
alpar@1
|
340 |
ut_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w);
|
alpar@1
|
341 |
/* w := inv(U)*w */
|
alpar@1
|
342 |
u_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w);
|
alpar@1
|
343 |
/* y := P'*w */
|
alpar@1
|
344 |
for (i = 1; i <= m; i++) y[i] = w[P[m+i]];
|
alpar@1
|
345 |
xfree(w);
|
alpar@1
|
346 |
/* compute residual vector r = A*D*A'*y - h */
|
alpar@1
|
347 |
r = xcalloc(1+m, sizeof(double));
|
alpar@1
|
348 |
/* w := A'*y */
|
alpar@1
|
349 |
w = xcalloc(1+n, sizeof(double));
|
alpar@1
|
350 |
AT_by_vec(csa, y, w);
|
alpar@1
|
351 |
/* w := D*w */
|
alpar@1
|
352 |
for (j = 1; j <= n; j++) w[j] *= csa->D[j];
|
alpar@1
|
353 |
/* r := A*w */
|
alpar@1
|
354 |
A_by_vec(csa, w, r);
|
alpar@1
|
355 |
xfree(w);
|
alpar@1
|
356 |
/* r := r - h */
|
alpar@1
|
357 |
for (i = 1; i <= m; i++) r[i] -= h[i];
|
alpar@1
|
358 |
/* check for numeric stability */
|
alpar@1
|
359 |
for (i = 1; i <= m; i++)
|
alpar@1
|
360 |
{ if (fabs(r[i]) / (1.0 + fabs(h[i])) > 1e-4)
|
alpar@1
|
361 |
{ ret = 1;
|
alpar@1
|
362 |
break;
|
alpar@1
|
363 |
}
|
alpar@1
|
364 |
}
|
alpar@1
|
365 |
xfree(h);
|
alpar@1
|
366 |
xfree(r);
|
alpar@1
|
367 |
return ret;
|
alpar@1
|
368 |
}
|
alpar@1
|
369 |
|
alpar@1
|
370 |
/***********************************************************************
|
alpar@1
|
371 |
* solve_NS - solve Newtonian system
|
alpar@1
|
372 |
*
|
alpar@1
|
373 |
* This routine solves the Newtonian system:
|
alpar@1
|
374 |
*
|
alpar@1
|
375 |
* A*dx = p
|
alpar@1
|
376 |
*
|
alpar@1
|
377 |
* A'*dy + dz = q
|
alpar@1
|
378 |
*
|
alpar@1
|
379 |
* Z*dx + X*dz = r
|
alpar@1
|
380 |
*
|
alpar@1
|
381 |
* where X = diag(x[j]), Z = diag(z[j]), by reducing it to the normal
|
alpar@1
|
382 |
* equation system:
|
alpar@1
|
383 |
*
|
alpar@1
|
384 |
* (A*inv(Z)*X*A')*dy = A*inv(Z)*(X*q-r)+p
|
alpar@1
|
385 |
*
|
alpar@1
|
386 |
* (it is assumed that the matrix A*inv(Z)*X*A' has been factorized by
|
alpar@1
|
387 |
* the routine decomp_NE).
|
alpar@1
|
388 |
*
|
alpar@1
|
389 |
* Once vector dy has been computed the routine computes vectors dx and
|
alpar@1
|
390 |
* dz as follows:
|
alpar@1
|
391 |
*
|
alpar@1
|
392 |
* dx = inv(Z)*(X*(A'*dy-q)+r)
|
alpar@1
|
393 |
*
|
alpar@1
|
394 |
* dz = inv(X)*(r-Z*dx)
|
alpar@1
|
395 |
*
|
alpar@1
|
396 |
* The routine solve_NS returns the same code which was reported by the
|
alpar@1
|
397 |
* routine solve_NE (see above). */
|
alpar@1
|
398 |
|
alpar@1
|
399 |
static int solve_NS(struct csa *csa, double p[], double q[], double r[],
|
alpar@1
|
400 |
double dx[], double dy[], double dz[])
|
alpar@1
|
401 |
{ int m = csa->m;
|
alpar@1
|
402 |
int n = csa->n;
|
alpar@1
|
403 |
double *x = csa->x;
|
alpar@1
|
404 |
double *z = csa->z;
|
alpar@1
|
405 |
int i, j, ret;
|
alpar@1
|
406 |
double *w = dx;
|
alpar@1
|
407 |
/* compute the vector of right-hand sides A*inv(Z)*(X*q-r)+p for
|
alpar@1
|
408 |
the normal equation system */
|
alpar@1
|
409 |
for (j = 1; j <= n; j++)
|
alpar@1
|
410 |
w[j] = (x[j] * q[j] - r[j]) / z[j];
|
alpar@1
|
411 |
A_by_vec(csa, w, dy);
|
alpar@1
|
412 |
for (i = 1; i <= m; i++) dy[i] += p[i];
|
alpar@1
|
413 |
/* solve the normal equation system to compute vector dy */
|
alpar@1
|
414 |
ret = solve_NE(csa, dy);
|
alpar@1
|
415 |
/* compute vectors dx and dz */
|
alpar@1
|
416 |
AT_by_vec(csa, dy, dx);
|
alpar@1
|
417 |
for (j = 1; j <= n; j++)
|
alpar@1
|
418 |
{ dx[j] = (x[j] * (dx[j] - q[j]) + r[j]) / z[j];
|
alpar@1
|
419 |
dz[j] = (r[j] - z[j] * dx[j]) / x[j];
|
alpar@1
|
420 |
}
|
alpar@1
|
421 |
return ret;
|
alpar@1
|
422 |
}
|
alpar@1
|
423 |
|
alpar@1
|
424 |
/***********************************************************************
|
alpar@1
|
425 |
* initial_point - choose initial point using Mehrotra's heuristic
|
alpar@1
|
426 |
*
|
alpar@1
|
427 |
* This routine chooses a starting point using a heuristic proposed in
|
alpar@1
|
428 |
* the paper:
|
alpar@1
|
429 |
*
|
alpar@1
|
430 |
* S. Mehrotra. On the implementation of a primal-dual interior point
|
alpar@1
|
431 |
* method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.
|
alpar@1
|
432 |
*
|
alpar@1
|
433 |
* The starting point x in the primal space is chosen as a solution of
|
alpar@1
|
434 |
* the following least squares problem:
|
alpar@1
|
435 |
*
|
alpar@1
|
436 |
* minimize ||x||
|
alpar@1
|
437 |
*
|
alpar@1
|
438 |
* subject to A*x = b
|
alpar@1
|
439 |
*
|
alpar@1
|
440 |
* which can be computed explicitly as follows:
|
alpar@1
|
441 |
*
|
alpar@1
|
442 |
* x = A'*inv(A*A')*b
|
alpar@1
|
443 |
*
|
alpar@1
|
444 |
* Similarly, the starting point (y, z) in the dual space is chosen as
|
alpar@1
|
445 |
* a solution of the following least squares problem:
|
alpar@1
|
446 |
*
|
alpar@1
|
447 |
* minimize ||z||
|
alpar@1
|
448 |
*
|
alpar@1
|
449 |
* subject to A'*y + z = c
|
alpar@1
|
450 |
*
|
alpar@1
|
451 |
* which can be computed explicitly as follows:
|
alpar@1
|
452 |
*
|
alpar@1
|
453 |
* y = inv(A*A')*A*c
|
alpar@1
|
454 |
*
|
alpar@1
|
455 |
* z = c - A'*y
|
alpar@1
|
456 |
*
|
alpar@1
|
457 |
* However, some components of the vectors x and z may be non-positive
|
alpar@1
|
458 |
* or close to zero, so the routine uses a Mehrotra's heuristic to find
|
alpar@1
|
459 |
* a more appropriate starting point. */
|
alpar@1
|
460 |
|
alpar@1
|
461 |
static void initial_point(struct csa *csa)
|
alpar@1
|
462 |
{ int m = csa->m;
|
alpar@1
|
463 |
int n = csa->n;
|
alpar@1
|
464 |
double *b = csa->b;
|
alpar@1
|
465 |
double *c = csa->c;
|
alpar@1
|
466 |
double *x = csa->x;
|
alpar@1
|
467 |
double *y = csa->y;
|
alpar@1
|
468 |
double *z = csa->z;
|
alpar@1
|
469 |
double *D = csa->D;
|
alpar@1
|
470 |
int i, j;
|
alpar@1
|
471 |
double dp, dd, ex, ez, xz;
|
alpar@1
|
472 |
/* factorize A*A' */
|
alpar@1
|
473 |
for (j = 1; j <= n; j++) D[j] = 1.0;
|
alpar@1
|
474 |
decomp_NE(csa);
|
alpar@1
|
475 |
/* x~ = A'*inv(A*A')*b */
|
alpar@1
|
476 |
for (i = 1; i <= m; i++) y[i] = b[i];
|
alpar@1
|
477 |
solve_NE(csa, y);
|
alpar@1
|
478 |
AT_by_vec(csa, y, x);
|
alpar@1
|
479 |
/* y~ = inv(A*A')*A*c */
|
alpar@1
|
480 |
A_by_vec(csa, c, y);
|
alpar@1
|
481 |
solve_NE(csa, y);
|
alpar@1
|
482 |
/* z~ = c - A'*y~ */
|
alpar@1
|
483 |
AT_by_vec(csa, y,z);
|
alpar@1
|
484 |
for (j = 1; j <= n; j++) z[j] = c[j] - z[j];
|
alpar@1
|
485 |
/* use Mehrotra's heuristic in order to choose more appropriate
|
alpar@1
|
486 |
starting point with positive components of vectors x and z */
|
alpar@1
|
487 |
dp = dd = 0.0;
|
alpar@1
|
488 |
for (j = 1; j <= n; j++)
|
alpar@1
|
489 |
{ if (dp < -1.5 * x[j]) dp = -1.5 * x[j];
|
alpar@1
|
490 |
if (dd < -1.5 * z[j]) dd = -1.5 * z[j];
|
alpar@1
|
491 |
}
|
alpar@1
|
492 |
/* note that b = 0 involves x = 0, and c = 0 involves y = 0 and
|
alpar@1
|
493 |
z = 0, so we need to be careful */
|
alpar@1
|
494 |
if (dp == 0.0) dp = 1.5;
|
alpar@1
|
495 |
if (dd == 0.0) dd = 1.5;
|
alpar@1
|
496 |
ex = ez = xz = 0.0;
|
alpar@1
|
497 |
for (j = 1; j <= n; j++)
|
alpar@1
|
498 |
{ ex += (x[j] + dp);
|
alpar@1
|
499 |
ez += (z[j] + dd);
|
alpar@1
|
500 |
xz += (x[j] + dp) * (z[j] + dd);
|
alpar@1
|
501 |
}
|
alpar@1
|
502 |
dp += 0.5 * (xz / ez);
|
alpar@1
|
503 |
dd += 0.5 * (xz / ex);
|
alpar@1
|
504 |
for (j = 1; j <= n; j++)
|
alpar@1
|
505 |
{ x[j] += dp;
|
alpar@1
|
506 |
z[j] += dd;
|
alpar@1
|
507 |
xassert(x[j] > 0.0 && z[j] > 0.0);
|
alpar@1
|
508 |
}
|
alpar@1
|
509 |
return;
|
alpar@1
|
510 |
}
|
alpar@1
|
511 |
|
alpar@1
|
512 |
/***********************************************************************
|
alpar@1
|
513 |
* basic_info - perform basic computations at the current point
|
alpar@1
|
514 |
*
|
alpar@1
|
515 |
* This routine computes the following quantities at the current point:
|
alpar@1
|
516 |
*
|
alpar@1
|
517 |
* 1) value of the objective function:
|
alpar@1
|
518 |
*
|
alpar@1
|
519 |
* F = c'*x + c[0]
|
alpar@1
|
520 |
*
|
alpar@1
|
521 |
* 2) relative primal infeasibility:
|
alpar@1
|
522 |
*
|
alpar@1
|
523 |
* rpi = ||A*x-b|| / (1+||b||)
|
alpar@1
|
524 |
*
|
alpar@1
|
525 |
* 3) relative dual infeasibility:
|
alpar@1
|
526 |
*
|
alpar@1
|
527 |
* rdi = ||A'*y+z-c|| / (1+||c||)
|
alpar@1
|
528 |
*
|
alpar@1
|
529 |
* 4) primal-dual gap (relative difference between the primal and the
|
alpar@1
|
530 |
* dual objective function values):
|
alpar@1
|
531 |
*
|
alpar@1
|
532 |
* gap = |c'*x-b'*y| / (1+|c'*x|)
|
alpar@1
|
533 |
*
|
alpar@1
|
534 |
* 5) merit function:
|
alpar@1
|
535 |
*
|
alpar@1
|
536 |
* phi = ||A*x-b|| / max(1,||b||) + ||A'*y+z-c|| / max(1,||c||) +
|
alpar@1
|
537 |
*
|
alpar@1
|
538 |
* + |c'*x-b'*y| / max(1,||b||,||c||)
|
alpar@1
|
539 |
*
|
alpar@1
|
540 |
* 6) duality measure:
|
alpar@1
|
541 |
*
|
alpar@1
|
542 |
* mu = x'*z / n
|
alpar@1
|
543 |
*
|
alpar@1
|
544 |
* 7) the ratio of infeasibility to mu:
|
alpar@1
|
545 |
*
|
alpar@1
|
546 |
* rmu = max(||A*x-b||,||A'*y+z-c||) / mu
|
alpar@1
|
547 |
*
|
alpar@1
|
548 |
* where ||*|| denotes euclidian norm, *' denotes transposition. */
|
alpar@1
|
549 |
|
alpar@1
|
550 |
static void basic_info(struct csa *csa)
|
alpar@1
|
551 |
{ int m = csa->m;
|
alpar@1
|
552 |
int n = csa->n;
|
alpar@1
|
553 |
double *b = csa->b;
|
alpar@1
|
554 |
double *c = csa->c;
|
alpar@1
|
555 |
double *x = csa->x;
|
alpar@1
|
556 |
double *y = csa->y;
|
alpar@1
|
557 |
double *z = csa->z;
|
alpar@1
|
558 |
int i, j;
|
alpar@1
|
559 |
double norm1, bnorm, norm2, cnorm, cx, by, *work, temp;
|
alpar@1
|
560 |
/* compute value of the objective function */
|
alpar@1
|
561 |
temp = c[0];
|
alpar@1
|
562 |
for (j = 1; j <= n; j++) temp += c[j] * x[j];
|
alpar@1
|
563 |
csa->obj = temp;
|
alpar@1
|
564 |
/* norm1 = ||A*x-b|| */
|
alpar@1
|
565 |
work = xcalloc(1+m, sizeof(double));
|
alpar@1
|
566 |
A_by_vec(csa, x, work);
|
alpar@1
|
567 |
norm1 = 0.0;
|
alpar@1
|
568 |
for (i = 1; i <= m; i++)
|
alpar@1
|
569 |
norm1 += (work[i] - b[i]) * (work[i] - b[i]);
|
alpar@1
|
570 |
norm1 = sqrt(norm1);
|
alpar@1
|
571 |
xfree(work);
|
alpar@1
|
572 |
/* bnorm = ||b|| */
|
alpar@1
|
573 |
bnorm = 0.0;
|
alpar@1
|
574 |
for (i = 1; i <= m; i++) bnorm += b[i] * b[i];
|
alpar@1
|
575 |
bnorm = sqrt(bnorm);
|
alpar@1
|
576 |
/* compute relative primal infeasibility */
|
alpar@1
|
577 |
csa->rpi = norm1 / (1.0 + bnorm);
|
alpar@1
|
578 |
/* norm2 = ||A'*y+z-c|| */
|
alpar@1
|
579 |
work = xcalloc(1+n, sizeof(double));
|
alpar@1
|
580 |
AT_by_vec(csa, y, work);
|
alpar@1
|
581 |
norm2 = 0.0;
|
alpar@1
|
582 |
for (j = 1; j <= n; j++)
|
alpar@1
|
583 |
norm2 += (work[j] + z[j] - c[j]) * (work[j] + z[j] - c[j]);
|
alpar@1
|
584 |
norm2 = sqrt(norm2);
|
alpar@1
|
585 |
xfree(work);
|
alpar@1
|
586 |
/* cnorm = ||c|| */
|
alpar@1
|
587 |
cnorm = 0.0;
|
alpar@1
|
588 |
for (j = 1; j <= n; j++) cnorm += c[j] * c[j];
|
alpar@1
|
589 |
cnorm = sqrt(cnorm);
|
alpar@1
|
590 |
/* compute relative dual infeasibility */
|
alpar@1
|
591 |
csa->rdi = norm2 / (1.0 + cnorm);
|
alpar@1
|
592 |
/* by = b'*y */
|
alpar@1
|
593 |
by = 0.0;
|
alpar@1
|
594 |
for (i = 1; i <= m; i++) by += b[i] * y[i];
|
alpar@1
|
595 |
/* cx = c'*x */
|
alpar@1
|
596 |
cx = 0.0;
|
alpar@1
|
597 |
for (j = 1; j <= n; j++) cx += c[j] * x[j];
|
alpar@1
|
598 |
/* compute primal-dual gap */
|
alpar@1
|
599 |
csa->gap = fabs(cx - by) / (1.0 + fabs(cx));
|
alpar@1
|
600 |
/* compute merit function */
|
alpar@1
|
601 |
csa->phi = 0.0;
|
alpar@1
|
602 |
csa->phi += norm1 / (bnorm > 1.0 ? bnorm : 1.0);
|
alpar@1
|
603 |
csa->phi += norm2 / (cnorm > 1.0 ? cnorm : 1.0);
|
alpar@1
|
604 |
temp = 1.0;
|
alpar@1
|
605 |
if (temp < bnorm) temp = bnorm;
|
alpar@1
|
606 |
if (temp < cnorm) temp = cnorm;
|
alpar@1
|
607 |
csa->phi += fabs(cx - by) / temp;
|
alpar@1
|
608 |
/* compute duality measure */
|
alpar@1
|
609 |
temp = 0.0;
|
alpar@1
|
610 |
for (j = 1; j <= n; j++) temp += x[j] * z[j];
|
alpar@1
|
611 |
csa->mu = temp / (double)n;
|
alpar@1
|
612 |
/* compute the ratio of infeasibility to mu */
|
alpar@1
|
613 |
csa->rmu = (norm1 > norm2 ? norm1 : norm2) / csa->mu;
|
alpar@1
|
614 |
return;
|
alpar@1
|
615 |
}
|
alpar@1
|
616 |
|
alpar@1
|
617 |
/***********************************************************************
|
alpar@1
|
618 |
* make_step - compute next point using Mehrotra's technique
|
alpar@1
|
619 |
*
|
alpar@1
|
620 |
* This routine computes the next point using the predictor-corrector
|
alpar@1
|
621 |
* technique proposed in the paper:
|
alpar@1
|
622 |
*
|
alpar@1
|
623 |
* S. Mehrotra. On the implementation of a primal-dual interior point
|
alpar@1
|
624 |
* method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.
|
alpar@1
|
625 |
*
|
alpar@1
|
626 |
* At first, the routine computes so called affine scaling (predictor)
|
alpar@1
|
627 |
* direction (dx_aff,dy_aff,dz_aff) which is a solution of the system:
|
alpar@1
|
628 |
*
|
alpar@1
|
629 |
* A*dx_aff = b - A*x
|
alpar@1
|
630 |
*
|
alpar@1
|
631 |
* A'*dy_aff + dz_aff = c - A'*y - z
|
alpar@1
|
632 |
*
|
alpar@1
|
633 |
* Z*dx_aff + X*dz_aff = - X*Z*e
|
alpar@1
|
634 |
*
|
alpar@1
|
635 |
* where (x,y,z) is the current point, X = diag(x[j]), Z = diag(z[j]),
|
alpar@1
|
636 |
* e = (1,...,1)'.
|
alpar@1
|
637 |
*
|
alpar@1
|
638 |
* Then, the routine computes the centering parameter sigma, using the
|
alpar@1
|
639 |
* following Mehrotra's heuristic:
|
alpar@1
|
640 |
*
|
alpar@1
|
641 |
* alfa_aff_p = inf{0 <= alfa <= 1 | x+alfa*dx_aff >= 0}
|
alpar@1
|
642 |
*
|
alpar@1
|
643 |
* alfa_aff_d = inf{0 <= alfa <= 1 | z+alfa*dz_aff >= 0}
|
alpar@1
|
644 |
*
|
alpar@1
|
645 |
* mu_aff = (x+alfa_aff_p*dx_aff)'*(z+alfa_aff_d*dz_aff)/n
|
alpar@1
|
646 |
*
|
alpar@1
|
647 |
* sigma = (mu_aff/mu)^3
|
alpar@1
|
648 |
*
|
alpar@1
|
649 |
* where alfa_aff_p is the maximal stepsize along the affine scaling
|
alpar@1
|
650 |
* direction in the primal space, alfa_aff_d is the maximal stepsize
|
alpar@1
|
651 |
* along the same direction in the dual space.
|
alpar@1
|
652 |
*
|
alpar@1
|
653 |
* After determining sigma the routine computes so called centering
|
alpar@1
|
654 |
* (corrector) direction (dx_cc,dy_cc,dz_cc) which is the solution of
|
alpar@1
|
655 |
* the system:
|
alpar@1
|
656 |
*
|
alpar@1
|
657 |
* A*dx_cc = 0
|
alpar@1
|
658 |
*
|
alpar@1
|
659 |
* A'*dy_cc + dz_cc = 0
|
alpar@1
|
660 |
*
|
alpar@1
|
661 |
* Z*dx_cc + X*dz_cc = sigma*mu*e - X*Z*e
|
alpar@1
|
662 |
*
|
alpar@1
|
663 |
* Finally, the routine computes the combined direction
|
alpar@1
|
664 |
*
|
alpar@1
|
665 |
* (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc)
|
alpar@1
|
666 |
*
|
alpar@1
|
667 |
* and determines maximal primal and dual stepsizes along the combined
|
alpar@1
|
668 |
* direction:
|
alpar@1
|
669 |
*
|
alpar@1
|
670 |
* alfa_max_p = inf{0 <= alfa <= 1 | x+alfa*dx >= 0}
|
alpar@1
|
671 |
*
|
alpar@1
|
672 |
* alfa_max_d = inf{0 <= alfa <= 1 | z+alfa*dz >= 0}
|
alpar@1
|
673 |
*
|
alpar@1
|
674 |
* In order to prevent the next point to be too close to the boundary
|
alpar@1
|
675 |
* of the positive ortant, the routine decreases maximal stepsizes:
|
alpar@1
|
676 |
*
|
alpar@1
|
677 |
* alfa_p = gamma_p * alfa_max_p
|
alpar@1
|
678 |
*
|
alpar@1
|
679 |
* alfa_d = gamma_d * alfa_max_d
|
alpar@1
|
680 |
*
|
alpar@1
|
681 |
* where gamma_p and gamma_d are scaling factors, and computes the next
|
alpar@1
|
682 |
* point:
|
alpar@1
|
683 |
*
|
alpar@1
|
684 |
* x_new = x + alfa_p * dx
|
alpar@1
|
685 |
*
|
alpar@1
|
686 |
* y_new = y + alfa_d * dy
|
alpar@1
|
687 |
*
|
alpar@1
|
688 |
* z_new = z + alfa_d * dz
|
alpar@1
|
689 |
*
|
alpar@1
|
690 |
* which becomes the current point on the next iteration. */
|
alpar@1
|
691 |
|
alpar@1
|
692 |
static int make_step(struct csa *csa)
|
alpar@1
|
693 |
{ int m = csa->m;
|
alpar@1
|
694 |
int n = csa->n;
|
alpar@1
|
695 |
double *b = csa->b;
|
alpar@1
|
696 |
double *c = csa->c;
|
alpar@1
|
697 |
double *x = csa->x;
|
alpar@1
|
698 |
double *y = csa->y;
|
alpar@1
|
699 |
double *z = csa->z;
|
alpar@1
|
700 |
double *dx_aff = csa->dx_aff;
|
alpar@1
|
701 |
double *dy_aff = csa->dy_aff;
|
alpar@1
|
702 |
double *dz_aff = csa->dz_aff;
|
alpar@1
|
703 |
double *dx_cc = csa->dx_cc;
|
alpar@1
|
704 |
double *dy_cc = csa->dy_cc;
|
alpar@1
|
705 |
double *dz_cc = csa->dz_cc;
|
alpar@1
|
706 |
double *dx = csa->dx;
|
alpar@1
|
707 |
double *dy = csa->dy;
|
alpar@1
|
708 |
double *dz = csa->dz;
|
alpar@1
|
709 |
int i, j, ret = 0;
|
alpar@1
|
710 |
double temp, gamma_p, gamma_d, *p, *q, *r;
|
alpar@1
|
711 |
/* allocate working arrays */
|
alpar@1
|
712 |
p = xcalloc(1+m, sizeof(double));
|
alpar@1
|
713 |
q = xcalloc(1+n, sizeof(double));
|
alpar@1
|
714 |
r = xcalloc(1+n, sizeof(double));
|
alpar@1
|
715 |
/* p = b - A*x */
|
alpar@1
|
716 |
A_by_vec(csa, x, p);
|
alpar@1
|
717 |
for (i = 1; i <= m; i++) p[i] = b[i] - p[i];
|
alpar@1
|
718 |
/* q = c - A'*y - z */
|
alpar@1
|
719 |
AT_by_vec(csa, y,q);
|
alpar@1
|
720 |
for (j = 1; j <= n; j++) q[j] = c[j] - q[j] - z[j];
|
alpar@1
|
721 |
/* r = - X * Z * e */
|
alpar@1
|
722 |
for (j = 1; j <= n; j++) r[j] = - x[j] * z[j];
|
alpar@1
|
723 |
/* solve the first Newtonian system */
|
alpar@1
|
724 |
if (solve_NS(csa, p, q, r, dx_aff, dy_aff, dz_aff))
|
alpar@1
|
725 |
{ ret = 1;
|
alpar@1
|
726 |
goto done;
|
alpar@1
|
727 |
}
|
alpar@1
|
728 |
/* alfa_aff_p = inf{0 <= alfa <= 1 | x + alfa*dx_aff >= 0} */
|
alpar@1
|
729 |
/* alfa_aff_d = inf{0 <= alfa <= 1 | z + alfa*dz_aff >= 0} */
|
alpar@1
|
730 |
csa->alfa_aff_p = csa->alfa_aff_d = 1.0;
|
alpar@1
|
731 |
for (j = 1; j <= n; j++)
|
alpar@1
|
732 |
{ if (dx_aff[j] < 0.0)
|
alpar@1
|
733 |
{ temp = - x[j] / dx_aff[j];
|
alpar@1
|
734 |
if (csa->alfa_aff_p > temp) csa->alfa_aff_p = temp;
|
alpar@1
|
735 |
}
|
alpar@1
|
736 |
if (dz_aff[j] < 0.0)
|
alpar@1
|
737 |
{ temp = - z[j] / dz_aff[j];
|
alpar@1
|
738 |
if (csa->alfa_aff_d > temp) csa->alfa_aff_d = temp;
|
alpar@1
|
739 |
}
|
alpar@1
|
740 |
}
|
alpar@1
|
741 |
/* mu_aff = (x+alfa_aff_p*dx_aff)' * (z+alfa_aff_d*dz_aff) / n */
|
alpar@1
|
742 |
temp = 0.0;
|
alpar@1
|
743 |
for (j = 1; j <= n; j++)
|
alpar@1
|
744 |
temp += (x[j] + csa->alfa_aff_p * dx_aff[j]) *
|
alpar@1
|
745 |
(z[j] + csa->alfa_aff_d * dz_aff[j]);
|
alpar@1
|
746 |
csa->mu_aff = temp / (double)n;
|
alpar@1
|
747 |
/* sigma = (mu_aff/mu)^3 */
|
alpar@1
|
748 |
temp = csa->mu_aff / csa->mu;
|
alpar@1
|
749 |
csa->sigma = temp * temp * temp;
|
alpar@1
|
750 |
/* p = 0 */
|
alpar@1
|
751 |
for (i = 1; i <= m; i++) p[i] = 0.0;
|
alpar@1
|
752 |
/* q = 0 */
|
alpar@1
|
753 |
for (j = 1; j <= n; j++) q[j] = 0.0;
|
alpar@1
|
754 |
/* r = sigma * mu * e - X * Z * e */
|
alpar@1
|
755 |
for (j = 1; j <= n; j++)
|
alpar@1
|
756 |
r[j] = csa->sigma * csa->mu - dx_aff[j] * dz_aff[j];
|
alpar@1
|
757 |
/* solve the second Newtonian system with the same coefficients
|
alpar@1
|
758 |
but with altered right-hand sides */
|
alpar@1
|
759 |
if (solve_NS(csa, p, q, r, dx_cc, dy_cc, dz_cc))
|
alpar@1
|
760 |
{ ret = 1;
|
alpar@1
|
761 |
goto done;
|
alpar@1
|
762 |
}
|
alpar@1
|
763 |
/* (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc) */
|
alpar@1
|
764 |
for (j = 1; j <= n; j++) dx[j] = dx_aff[j] + dx_cc[j];
|
alpar@1
|
765 |
for (i = 1; i <= m; i++) dy[i] = dy_aff[i] + dy_cc[i];
|
alpar@1
|
766 |
for (j = 1; j <= n; j++) dz[j] = dz_aff[j] + dz_cc[j];
|
alpar@1
|
767 |
/* alfa_max_p = inf{0 <= alfa <= 1 | x + alfa*dx >= 0} */
|
alpar@1
|
768 |
/* alfa_max_d = inf{0 <= alfa <= 1 | z + alfa*dz >= 0} */
|
alpar@1
|
769 |
csa->alfa_max_p = csa->alfa_max_d = 1.0;
|
alpar@1
|
770 |
for (j = 1; j <= n; j++)
|
alpar@1
|
771 |
{ if (dx[j] < 0.0)
|
alpar@1
|
772 |
{ temp = - x[j] / dx[j];
|
alpar@1
|
773 |
if (csa->alfa_max_p > temp) csa->alfa_max_p = temp;
|
alpar@1
|
774 |
}
|
alpar@1
|
775 |
if (dz[j] < 0.0)
|
alpar@1
|
776 |
{ temp = - z[j] / dz[j];
|
alpar@1
|
777 |
if (csa->alfa_max_d > temp) csa->alfa_max_d = temp;
|
alpar@1
|
778 |
}
|
alpar@1
|
779 |
}
|
alpar@1
|
780 |
/* determine scale factors (not implemented yet) */
|
alpar@1
|
781 |
gamma_p = 0.90;
|
alpar@1
|
782 |
gamma_d = 0.90;
|
alpar@1
|
783 |
/* compute the next point */
|
alpar@1
|
784 |
for (j = 1; j <= n; j++)
|
alpar@1
|
785 |
{ x[j] += gamma_p * csa->alfa_max_p * dx[j];
|
alpar@1
|
786 |
xassert(x[j] > 0.0);
|
alpar@1
|
787 |
}
|
alpar@1
|
788 |
for (i = 1; i <= m; i++)
|
alpar@1
|
789 |
y[i] += gamma_d * csa->alfa_max_d * dy[i];
|
alpar@1
|
790 |
for (j = 1; j <= n; j++)
|
alpar@1
|
791 |
{ z[j] += gamma_d * csa->alfa_max_d * dz[j];
|
alpar@1
|
792 |
xassert(z[j] > 0.0);
|
alpar@1
|
793 |
}
|
alpar@1
|
794 |
done: /* free working arrays */
|
alpar@1
|
795 |
xfree(p);
|
alpar@1
|
796 |
xfree(q);
|
alpar@1
|
797 |
xfree(r);
|
alpar@1
|
798 |
return ret;
|
alpar@1
|
799 |
}
|
alpar@1
|
800 |
|
alpar@1
|
801 |
/***********************************************************************
|
alpar@1
|
802 |
* terminate - deallocate common storage area
|
alpar@1
|
803 |
*
|
alpar@1
|
804 |
* This routine frees all memory allocated to the common storage area
|
alpar@1
|
805 |
* used by interior-point method routines. */
|
alpar@1
|
806 |
|
alpar@1
|
807 |
static void terminate(struct csa *csa)
|
alpar@1
|
808 |
{ xfree(csa->D);
|
alpar@1
|
809 |
xfree(csa->P);
|
alpar@1
|
810 |
xfree(csa->S_ptr);
|
alpar@1
|
811 |
xfree(csa->S_ind);
|
alpar@1
|
812 |
xfree(csa->S_val);
|
alpar@1
|
813 |
xfree(csa->S_diag);
|
alpar@1
|
814 |
xfree(csa->U_ptr);
|
alpar@1
|
815 |
xfree(csa->U_ind);
|
alpar@1
|
816 |
xfree(csa->U_val);
|
alpar@1
|
817 |
xfree(csa->U_diag);
|
alpar@1
|
818 |
xfree(csa->phi_min);
|
alpar@1
|
819 |
xfree(csa->best_x);
|
alpar@1
|
820 |
xfree(csa->best_y);
|
alpar@1
|
821 |
xfree(csa->best_z);
|
alpar@1
|
822 |
xfree(csa->dx_aff);
|
alpar@1
|
823 |
xfree(csa->dy_aff);
|
alpar@1
|
824 |
xfree(csa->dz_aff);
|
alpar@1
|
825 |
xfree(csa->dx_cc);
|
alpar@1
|
826 |
xfree(csa->dy_cc);
|
alpar@1
|
827 |
xfree(csa->dz_cc);
|
alpar@1
|
828 |
return;
|
alpar@1
|
829 |
}
|
alpar@1
|
830 |
|
alpar@1
|
831 |
/***********************************************************************
|
alpar@1
|
832 |
* ipm_main - main interior-point method routine
|
alpar@1
|
833 |
*
|
alpar@1
|
834 |
* This is a main routine of the primal-dual interior-point method.
|
alpar@1
|
835 |
*
|
alpar@1
|
836 |
* The routine ipm_main returns one of the following codes:
|
alpar@1
|
837 |
*
|
alpar@1
|
838 |
* 0 - optimal solution found;
|
alpar@1
|
839 |
* 1 - problem has no feasible (primal or dual) solution;
|
alpar@1
|
840 |
* 2 - no convergence;
|
alpar@1
|
841 |
* 3 - iteration limit exceeded;
|
alpar@1
|
842 |
* 4 - numeric instability on solving Newtonian system.
|
alpar@1
|
843 |
*
|
alpar@1
|
844 |
* In case of non-zero return code the routine returns the best point,
|
alpar@1
|
845 |
* which has been reached during optimization. */
|
alpar@1
|
846 |
|
alpar@1
|
847 |
static int ipm_main(struct csa *csa)
|
alpar@1
|
848 |
{ int m = csa->m;
|
alpar@1
|
849 |
int n = csa->n;
|
alpar@1
|
850 |
int i, j, status;
|
alpar@1
|
851 |
double temp;
|
alpar@1
|
852 |
/* choose initial point using Mehrotra's heuristic */
|
alpar@1
|
853 |
if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
854 |
xprintf("Guessing initial point...\n");
|
alpar@1
|
855 |
initial_point(csa);
|
alpar@1
|
856 |
/* main loop starts here */
|
alpar@1
|
857 |
if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
858 |
xprintf("Optimization begins...\n");
|
alpar@1
|
859 |
for (;;)
|
alpar@1
|
860 |
{ /* perform basic computations at the current point */
|
alpar@1
|
861 |
basic_info(csa);
|
alpar@1
|
862 |
/* save initial value of rmu */
|
alpar@1
|
863 |
if (csa->iter == 0) csa->rmu0 = csa->rmu;
|
alpar@1
|
864 |
/* accumulate values of min(phi[k]) and save the best point */
|
alpar@1
|
865 |
xassert(csa->iter <= ITER_MAX);
|
alpar@1
|
866 |
if (csa->iter == 0 || csa->phi_min[csa->iter-1] > csa->phi)
|
alpar@1
|
867 |
{ csa->phi_min[csa->iter] = csa->phi;
|
alpar@1
|
868 |
csa->best_iter = csa->iter;
|
alpar@1
|
869 |
for (j = 1; j <= n; j++) csa->best_x[j] = csa->x[j];
|
alpar@1
|
870 |
for (i = 1; i <= m; i++) csa->best_y[i] = csa->y[i];
|
alpar@1
|
871 |
for (j = 1; j <= n; j++) csa->best_z[j] = csa->z[j];
|
alpar@1
|
872 |
csa->best_obj = csa->obj;
|
alpar@1
|
873 |
}
|
alpar@1
|
874 |
else
|
alpar@1
|
875 |
csa->phi_min[csa->iter] = csa->phi_min[csa->iter-1];
|
alpar@1
|
876 |
/* display information at the current point */
|
alpar@1
|
877 |
if (csa->parm->msg_lev >= GLP_MSG_ON)
|
alpar@1
|
878 |
xprintf("%3d: obj = %17.9e; rpi = %8.1e; rdi = %8.1e; gap ="
|
alpar@1
|
879 |
" %8.1e\n", csa->iter, csa->obj, csa->rpi, csa->rdi,
|
alpar@1
|
880 |
csa->gap);
|
alpar@1
|
881 |
/* check if the current point is optimal */
|
alpar@1
|
882 |
if (csa->rpi < 1e-8 && csa->rdi < 1e-8 && csa->gap < 1e-8)
|
alpar@1
|
883 |
{ if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
884 |
xprintf("OPTIMAL SOLUTION FOUND\n");
|
alpar@1
|
885 |
status = 0;
|
alpar@1
|
886 |
break;
|
alpar@1
|
887 |
}
|
alpar@1
|
888 |
/* check if the problem has no feasible solution */
|
alpar@1
|
889 |
temp = 1e5 * csa->phi_min[csa->iter];
|
alpar@1
|
890 |
if (temp < 1e-8) temp = 1e-8;
|
alpar@1
|
891 |
if (csa->phi >= temp)
|
alpar@1
|
892 |
{ if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
893 |
xprintf("PROBLEM HAS NO FEASIBLE PRIMAL/DUAL SOLUTION\n")
|
alpar@1
|
894 |
;
|
alpar@1
|
895 |
status = 1;
|
alpar@1
|
896 |
break;
|
alpar@1
|
897 |
}
|
alpar@1
|
898 |
/* check for very slow convergence or divergence */
|
alpar@1
|
899 |
if (((csa->rpi >= 1e-8 || csa->rdi >= 1e-8) && csa->rmu /
|
alpar@1
|
900 |
csa->rmu0 >= 1e6) ||
|
alpar@1
|
901 |
(csa->iter >= 30 && csa->phi_min[csa->iter] >= 0.5 *
|
alpar@1
|
902 |
csa->phi_min[csa->iter - 30]))
|
alpar@1
|
903 |
{ if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
904 |
xprintf("NO CONVERGENCE; SEARCH TERMINATED\n");
|
alpar@1
|
905 |
status = 2;
|
alpar@1
|
906 |
break;
|
alpar@1
|
907 |
}
|
alpar@1
|
908 |
/* check for maximal number of iterations */
|
alpar@1
|
909 |
if (csa->iter == ITER_MAX)
|
alpar@1
|
910 |
{ if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
911 |
xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
|
alpar@1
|
912 |
status = 3;
|
alpar@1
|
913 |
break;
|
alpar@1
|
914 |
}
|
alpar@1
|
915 |
/* start the next iteration */
|
alpar@1
|
916 |
csa->iter++;
|
alpar@1
|
917 |
/* factorize normal equation system */
|
alpar@1
|
918 |
for (j = 1; j <= n; j++) csa->D[j] = csa->x[j] / csa->z[j];
|
alpar@1
|
919 |
decomp_NE(csa);
|
alpar@1
|
920 |
/* compute the next point using Mehrotra's predictor-corrector
|
alpar@1
|
921 |
technique */
|
alpar@1
|
922 |
if (make_step(csa))
|
alpar@1
|
923 |
{ if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
924 |
xprintf("NUMERIC INSTABILITY; SEARCH TERMINATED\n");
|
alpar@1
|
925 |
status = 4;
|
alpar@1
|
926 |
break;
|
alpar@1
|
927 |
}
|
alpar@1
|
928 |
}
|
alpar@1
|
929 |
/* restore the best point */
|
alpar@1
|
930 |
if (status != 0)
|
alpar@1
|
931 |
{ for (j = 1; j <= n; j++) csa->x[j] = csa->best_x[j];
|
alpar@1
|
932 |
for (i = 1; i <= m; i++) csa->y[i] = csa->best_y[i];
|
alpar@1
|
933 |
for (j = 1; j <= n; j++) csa->z[j] = csa->best_z[j];
|
alpar@1
|
934 |
if (csa->parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
935 |
xprintf("Best point %17.9e was reached on iteration %d\n",
|
alpar@1
|
936 |
csa->best_obj, csa->best_iter);
|
alpar@1
|
937 |
}
|
alpar@1
|
938 |
/* return to the calling program */
|
alpar@1
|
939 |
return status;
|
alpar@1
|
940 |
}
|
alpar@1
|
941 |
|
alpar@1
|
942 |
/***********************************************************************
|
alpar@1
|
943 |
* NAME
|
alpar@1
|
944 |
*
|
alpar@1
|
945 |
* ipm_solve - core LP solver based on the interior-point method
|
alpar@1
|
946 |
*
|
alpar@1
|
947 |
* SYNOPSIS
|
alpar@1
|
948 |
*
|
alpar@1
|
949 |
* #include "glpipm.h"
|
alpar@1
|
950 |
* int ipm_solve(glp_prob *P, const glp_iptcp *parm);
|
alpar@1
|
951 |
*
|
alpar@1
|
952 |
* DESCRIPTION
|
alpar@1
|
953 |
*
|
alpar@1
|
954 |
* The routine ipm_solve is a core LP solver based on the primal-dual
|
alpar@1
|
955 |
* interior-point method.
|
alpar@1
|
956 |
*
|
alpar@1
|
957 |
* The routine assumes the following standard formulation of LP problem
|
alpar@1
|
958 |
* to be solved:
|
alpar@1
|
959 |
*
|
alpar@1
|
960 |
* minimize
|
alpar@1
|
961 |
*
|
alpar@1
|
962 |
* F = c[0] + c[1]*x[1] + c[2]*x[2] + ... + c[n]*x[n]
|
alpar@1
|
963 |
*
|
alpar@1
|
964 |
* subject to linear constraints
|
alpar@1
|
965 |
*
|
alpar@1
|
966 |
* a[1,1]*x[1] + a[1,2]*x[2] + ... + a[1,n]*x[n] = b[1]
|
alpar@1
|
967 |
*
|
alpar@1
|
968 |
* a[2,1]*x[1] + a[2,2]*x[2] + ... + a[2,n]*x[n] = b[2]
|
alpar@1
|
969 |
*
|
alpar@1
|
970 |
* . . . . . .
|
alpar@1
|
971 |
*
|
alpar@1
|
972 |
* a[m,1]*x[1] + a[m,2]*x[2] + ... + a[m,n]*x[n] = b[m]
|
alpar@1
|
973 |
*
|
alpar@1
|
974 |
* and non-negative variables
|
alpar@1
|
975 |
*
|
alpar@1
|
976 |
* x[1] >= 0, x[2] >= 0, ..., x[n] >= 0
|
alpar@1
|
977 |
*
|
alpar@1
|
978 |
* where:
|
alpar@1
|
979 |
* F is the objective function;
|
alpar@1
|
980 |
* x[1], ..., x[n] are (structural) variables;
|
alpar@1
|
981 |
* c[0] is a constant term of the objective function;
|
alpar@1
|
982 |
* c[1], ..., c[n] are objective coefficients;
|
alpar@1
|
983 |
* a[1,1], ..., a[m,n] are constraint coefficients;
|
alpar@1
|
984 |
* b[1], ..., b[n] are right-hand sides.
|
alpar@1
|
985 |
*
|
alpar@1
|
986 |
* The solution is three vectors x, y, and z, which are stored by the
|
alpar@1
|
987 |
* routine in the arrays x, y, and z, respectively. These vectors
|
alpar@1
|
988 |
* correspond to the best primal-dual point found during optimization.
|
alpar@1
|
989 |
* They are approximate solution of the following system (which is the
|
alpar@1
|
990 |
* Karush-Kuhn-Tucker optimality conditions):
|
alpar@1
|
991 |
*
|
alpar@1
|
992 |
* A*x = b (primal feasibility condition)
|
alpar@1
|
993 |
*
|
alpar@1
|
994 |
* A'*y + z = c (dual feasibility condition)
|
alpar@1
|
995 |
*
|
alpar@1
|
996 |
* x'*z = 0 (primal-dual complementarity condition)
|
alpar@1
|
997 |
*
|
alpar@1
|
998 |
* x >= 0, z >= 0 (non-negativity condition)
|
alpar@1
|
999 |
*
|
alpar@1
|
1000 |
* where:
|
alpar@1
|
1001 |
* x[1], ..., x[n] are primal (structural) variables;
|
alpar@1
|
1002 |
* y[1], ..., y[m] are dual variables (Lagrange multipliers) for
|
alpar@1
|
1003 |
* equality constraints;
|
alpar@1
|
1004 |
* z[1], ..., z[n] are dual variables (Lagrange multipliers) for
|
alpar@1
|
1005 |
* non-negativity constraints.
|
alpar@1
|
1006 |
*
|
alpar@1
|
1007 |
* RETURNS
|
alpar@1
|
1008 |
*
|
alpar@1
|
1009 |
* 0 LP has been successfully solved.
|
alpar@1
|
1010 |
*
|
alpar@1
|
1011 |
* GLP_ENOCVG
|
alpar@1
|
1012 |
* No convergence.
|
alpar@1
|
1013 |
*
|
alpar@1
|
1014 |
* GLP_EITLIM
|
alpar@1
|
1015 |
* Iteration limit exceeded.
|
alpar@1
|
1016 |
*
|
alpar@1
|
1017 |
* GLP_EINSTAB
|
alpar@1
|
1018 |
* Numeric instability on solving Newtonian system.
|
alpar@1
|
1019 |
*
|
alpar@1
|
1020 |
* In case of non-zero return code the routine returns the best point,
|
alpar@1
|
1021 |
* which has been reached during optimization. */
|
alpar@1
|
1022 |
|
alpar@1
|
1023 |
int ipm_solve(glp_prob *P, const glp_iptcp *parm)
|
alpar@1
|
1024 |
{ struct csa _dsa, *csa = &_dsa;
|
alpar@1
|
1025 |
int m = P->m;
|
alpar@1
|
1026 |
int n = P->n;
|
alpar@1
|
1027 |
int nnz = P->nnz;
|
alpar@1
|
1028 |
GLPROW *row;
|
alpar@1
|
1029 |
GLPCOL *col;
|
alpar@1
|
1030 |
GLPAIJ *aij;
|
alpar@1
|
1031 |
int i, j, loc, ret, *A_ind, *A_ptr;
|
alpar@1
|
1032 |
double dir, *A_val, *b, *c, *x, *y, *z;
|
alpar@1
|
1033 |
xassert(m > 0);
|
alpar@1
|
1034 |
xassert(n > 0);
|
alpar@1
|
1035 |
/* allocate working arrays */
|
alpar@1
|
1036 |
A_ptr = xcalloc(1+m+1, sizeof(int));
|
alpar@1
|
1037 |
A_ind = xcalloc(1+nnz, sizeof(int));
|
alpar@1
|
1038 |
A_val = xcalloc(1+nnz, sizeof(double));
|
alpar@1
|
1039 |
b = xcalloc(1+m, sizeof(double));
|
alpar@1
|
1040 |
c = xcalloc(1+n, sizeof(double));
|
alpar@1
|
1041 |
x = xcalloc(1+n, sizeof(double));
|
alpar@1
|
1042 |
y = xcalloc(1+m, sizeof(double));
|
alpar@1
|
1043 |
z = xcalloc(1+n, sizeof(double));
|
alpar@1
|
1044 |
/* prepare rows and constraint coefficients */
|
alpar@1
|
1045 |
loc = 1;
|
alpar@1
|
1046 |
for (i = 1; i <= m; i++)
|
alpar@1
|
1047 |
{ row = P->row[i];
|
alpar@1
|
1048 |
xassert(row->type == GLP_FX);
|
alpar@1
|
1049 |
b[i] = row->lb * row->rii;
|
alpar@1
|
1050 |
A_ptr[i] = loc;
|
alpar@1
|
1051 |
for (aij = row->ptr; aij != NULL; aij = aij->r_next)
|
alpar@1
|
1052 |
{ A_ind[loc] = aij->col->j;
|
alpar@1
|
1053 |
A_val[loc] = row->rii * aij->val * aij->col->sjj;
|
alpar@1
|
1054 |
loc++;
|
alpar@1
|
1055 |
}
|
alpar@1
|
1056 |
}
|
alpar@1
|
1057 |
A_ptr[m+1] = loc;
|
alpar@1
|
1058 |
xassert(loc-1 == nnz);
|
alpar@1
|
1059 |
/* prepare columns and objective coefficients */
|
alpar@1
|
1060 |
if (P->dir == GLP_MIN)
|
alpar@1
|
1061 |
dir = +1.0;
|
alpar@1
|
1062 |
else if (P->dir == GLP_MAX)
|
alpar@1
|
1063 |
dir = -1.0;
|
alpar@1
|
1064 |
else
|
alpar@1
|
1065 |
xassert(P != P);
|
alpar@1
|
1066 |
c[0] = dir * P->c0;
|
alpar@1
|
1067 |
for (j = 1; j <= n; j++)
|
alpar@1
|
1068 |
{ col = P->col[j];
|
alpar@1
|
1069 |
xassert(col->type == GLP_LO && col->lb == 0.0);
|
alpar@1
|
1070 |
c[j] = dir * col->coef * col->sjj;
|
alpar@1
|
1071 |
}
|
alpar@1
|
1072 |
/* allocate and initialize the common storage area */
|
alpar@1
|
1073 |
csa->m = m;
|
alpar@1
|
1074 |
csa->n = n;
|
alpar@1
|
1075 |
csa->A_ptr = A_ptr;
|
alpar@1
|
1076 |
csa->A_ind = A_ind;
|
alpar@1
|
1077 |
csa->A_val = A_val;
|
alpar@1
|
1078 |
csa->b = b;
|
alpar@1
|
1079 |
csa->c = c;
|
alpar@1
|
1080 |
csa->x = x;
|
alpar@1
|
1081 |
csa->y = y;
|
alpar@1
|
1082 |
csa->z = z;
|
alpar@1
|
1083 |
csa->parm = parm;
|
alpar@1
|
1084 |
initialize(csa);
|
alpar@1
|
1085 |
/* solve LP with the interior-point method */
|
alpar@1
|
1086 |
ret = ipm_main(csa);
|
alpar@1
|
1087 |
/* deallocate the common storage area */
|
alpar@1
|
1088 |
terminate(csa);
|
alpar@1
|
1089 |
/* determine solution status */
|
alpar@1
|
1090 |
if (ret == 0)
|
alpar@1
|
1091 |
{ /* optimal solution found */
|
alpar@1
|
1092 |
P->ipt_stat = GLP_OPT;
|
alpar@1
|
1093 |
ret = 0;
|
alpar@1
|
1094 |
}
|
alpar@1
|
1095 |
else if (ret == 1)
|
alpar@1
|
1096 |
{ /* problem has no feasible (primal or dual) solution */
|
alpar@1
|
1097 |
P->ipt_stat = GLP_NOFEAS;
|
alpar@1
|
1098 |
ret = 0;
|
alpar@1
|
1099 |
}
|
alpar@1
|
1100 |
else if (ret == 2)
|
alpar@1
|
1101 |
{ /* no convergence */
|
alpar@1
|
1102 |
P->ipt_stat = GLP_INFEAS;
|
alpar@1
|
1103 |
ret = GLP_ENOCVG;
|
alpar@1
|
1104 |
}
|
alpar@1
|
1105 |
else if (ret == 3)
|
alpar@1
|
1106 |
{ /* iteration limit exceeded */
|
alpar@1
|
1107 |
P->ipt_stat = GLP_INFEAS;
|
alpar@1
|
1108 |
ret = GLP_EITLIM;
|
alpar@1
|
1109 |
}
|
alpar@1
|
1110 |
else if (ret == 4)
|
alpar@1
|
1111 |
{ /* numeric instability on solving Newtonian system */
|
alpar@1
|
1112 |
P->ipt_stat = GLP_INFEAS;
|
alpar@1
|
1113 |
ret = GLP_EINSTAB;
|
alpar@1
|
1114 |
}
|
alpar@1
|
1115 |
else
|
alpar@1
|
1116 |
xassert(ret != ret);
|
alpar@1
|
1117 |
/* store row solution components */
|
alpar@1
|
1118 |
for (i = 1; i <= m; i++)
|
alpar@1
|
1119 |
{ row = P->row[i];
|
alpar@1
|
1120 |
row->pval = row->lb;
|
alpar@1
|
1121 |
row->dval = dir * y[i] * row->rii;
|
alpar@1
|
1122 |
}
|
alpar@1
|
1123 |
/* store column solution components */
|
alpar@1
|
1124 |
P->ipt_obj = P->c0;
|
alpar@1
|
1125 |
for (j = 1; j <= n; j++)
|
alpar@1
|
1126 |
{ col = P->col[j];
|
alpar@1
|
1127 |
col->pval = x[j] * col->sjj;
|
alpar@1
|
1128 |
col->dval = dir * z[j] / col->sjj;
|
alpar@1
|
1129 |
P->ipt_obj += col->coef * col->pval;
|
alpar@1
|
1130 |
}
|
alpar@1
|
1131 |
/* free working arrays */
|
alpar@1
|
1132 |
xfree(A_ptr);
|
alpar@1
|
1133 |
xfree(A_ind);
|
alpar@1
|
1134 |
xfree(A_val);
|
alpar@1
|
1135 |
xfree(b);
|
alpar@1
|
1136 |
xfree(c);
|
alpar@1
|
1137 |
xfree(x);
|
alpar@1
|
1138 |
xfree(y);
|
alpar@1
|
1139 |
xfree(z);
|
alpar@1
|
1140 |
return ret;
|
alpar@1
|
1141 |
}
|
alpar@1
|
1142 |
|
alpar@1
|
1143 |
/* eof */
|