src/glpipm.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

- Generated files and doc/notes are removed
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 */