src/glpssx01.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
alpar@1
     1
/* glpssx01.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 "glpenv.h"
alpar@1
    26
#include "glpssx.h"
alpar@1
    27
#define xfault xerror
alpar@1
    28
alpar@1
    29
/*----------------------------------------------------------------------
alpar@1
    30
// ssx_create - create simplex solver workspace.
alpar@1
    31
//
alpar@1
    32
// This routine creates the workspace used by simplex solver routines,
alpar@1
    33
// and returns a pointer to it.
alpar@1
    34
//
alpar@1
    35
// Parameters m, n, and nnz specify, respectively, the number of rows,
alpar@1
    36
// columns, and non-zero constraint coefficients.
alpar@1
    37
//
alpar@1
    38
// This routine only allocates the memory for the workspace components,
alpar@1
    39
// so the workspace needs to be saturated by data. */
alpar@1
    40
alpar@1
    41
SSX *ssx_create(int m, int n, int nnz)
alpar@1
    42
{     SSX *ssx;
alpar@1
    43
      int i, j, k;
alpar@1
    44
      if (m < 1)
alpar@1
    45
         xfault("ssx_create: m = %d; invalid number of rows\n", m);
alpar@1
    46
      if (n < 1)
alpar@1
    47
         xfault("ssx_create: n = %d; invalid number of columns\n", n);
alpar@1
    48
      if (nnz < 0)
alpar@1
    49
         xfault("ssx_create: nnz = %d; invalid number of non-zero const"
alpar@1
    50
            "raint coefficients\n", nnz);
alpar@1
    51
      ssx = xmalloc(sizeof(SSX));
alpar@1
    52
      ssx->m = m;
alpar@1
    53
      ssx->n = n;
alpar@1
    54
      ssx->type = xcalloc(1+m+n, sizeof(int));
alpar@1
    55
      ssx->lb = xcalloc(1+m+n, sizeof(mpq_t));
alpar@1
    56
      for (k = 1; k <= m+n; k++) mpq_init(ssx->lb[k]);
alpar@1
    57
      ssx->ub = xcalloc(1+m+n, sizeof(mpq_t));
alpar@1
    58
      for (k = 1; k <= m+n; k++) mpq_init(ssx->ub[k]);
alpar@1
    59
      ssx->coef = xcalloc(1+m+n, sizeof(mpq_t));
alpar@1
    60
      for (k = 0; k <= m+n; k++) mpq_init(ssx->coef[k]);
alpar@1
    61
      ssx->A_ptr = xcalloc(1+n+1, sizeof(int));
alpar@1
    62
      ssx->A_ptr[n+1] = nnz+1;
alpar@1
    63
      ssx->A_ind = xcalloc(1+nnz, sizeof(int));
alpar@1
    64
      ssx->A_val = xcalloc(1+nnz, sizeof(mpq_t));
alpar@1
    65
      for (k = 1; k <= nnz; k++) mpq_init(ssx->A_val[k]);
alpar@1
    66
      ssx->stat = xcalloc(1+m+n, sizeof(int));
alpar@1
    67
      ssx->Q_row = xcalloc(1+m+n, sizeof(int));
alpar@1
    68
      ssx->Q_col = xcalloc(1+m+n, sizeof(int));
alpar@1
    69
      ssx->binv = bfx_create_binv();
alpar@1
    70
      ssx->bbar = xcalloc(1+m, sizeof(mpq_t));
alpar@1
    71
      for (i = 0; i <= m; i++) mpq_init(ssx->bbar[i]);
alpar@1
    72
      ssx->pi = xcalloc(1+m, sizeof(mpq_t));
alpar@1
    73
      for (i = 1; i <= m; i++) mpq_init(ssx->pi[i]);
alpar@1
    74
      ssx->cbar = xcalloc(1+n, sizeof(mpq_t));
alpar@1
    75
      for (j = 1; j <= n; j++) mpq_init(ssx->cbar[j]);
alpar@1
    76
      ssx->rho = xcalloc(1+m, sizeof(mpq_t));
alpar@1
    77
      for (i = 1; i <= m; i++) mpq_init(ssx->rho[i]);
alpar@1
    78
      ssx->ap = xcalloc(1+n, sizeof(mpq_t));
alpar@1
    79
      for (j = 1; j <= n; j++) mpq_init(ssx->ap[j]);
alpar@1
    80
      ssx->aq = xcalloc(1+m, sizeof(mpq_t));
alpar@1
    81
      for (i = 1; i <= m; i++) mpq_init(ssx->aq[i]);
alpar@1
    82
      mpq_init(ssx->delta);
alpar@1
    83
      return ssx;
alpar@1
    84
}
alpar@1
    85
alpar@1
    86
/*----------------------------------------------------------------------
alpar@1
    87
// ssx_factorize - factorize the current basis matrix.
alpar@1
    88
//
alpar@1
    89
// This routine computes factorization of the current basis matrix B
alpar@1
    90
// and returns the singularity flag. If the matrix B is non-singular,
alpar@1
    91
// the flag is zero, otherwise non-zero. */
alpar@1
    92
alpar@1
    93
static int basis_col(void *info, int j, int ind[], mpq_t val[])
alpar@1
    94
{     /* this auxiliary routine provides row indices and numeric values
alpar@1
    95
         of non-zero elements in j-th column of the matrix B */
alpar@1
    96
      SSX *ssx = info;
alpar@1
    97
      int m = ssx->m;
alpar@1
    98
      int n = ssx->n;
alpar@1
    99
      int *A_ptr = ssx->A_ptr;
alpar@1
   100
      int *A_ind = ssx->A_ind;
alpar@1
   101
      mpq_t *A_val = ssx->A_val;
alpar@1
   102
      int *Q_col = ssx->Q_col;
alpar@1
   103
      int k, len, ptr;
alpar@1
   104
      xassert(1 <= j && j <= m);
alpar@1
   105
      k = Q_col[j]; /* x[k] = xB[j] */
alpar@1
   106
      xassert(1 <= k && k <= m+n);
alpar@1
   107
      /* j-th column of the matrix B is k-th column of the augmented
alpar@1
   108
         constraint matrix (I | -A) */
alpar@1
   109
      if (k <= m)
alpar@1
   110
      {  /* it is a column of the unity matrix I */
alpar@1
   111
         len = 1, ind[1] = k, mpq_set_si(val[1], 1, 1);
alpar@1
   112
      }
alpar@1
   113
      else
alpar@1
   114
      {  /* it is a column of the original constraint matrix -A */
alpar@1
   115
         len = 0;
alpar@1
   116
         for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
alpar@1
   117
         {  len++;
alpar@1
   118
            ind[len] = A_ind[ptr];
alpar@1
   119
            mpq_neg(val[len], A_val[ptr]);
alpar@1
   120
         }
alpar@1
   121
      }
alpar@1
   122
      return len;
alpar@1
   123
}
alpar@1
   124
alpar@1
   125
int ssx_factorize(SSX *ssx)
alpar@1
   126
{     int ret;
alpar@1
   127
      ret = bfx_factorize(ssx->binv, ssx->m, basis_col, ssx);
alpar@1
   128
      return ret;
alpar@1
   129
}
alpar@1
   130
alpar@1
   131
/*----------------------------------------------------------------------
alpar@1
   132
// ssx_get_xNj - determine value of non-basic variable.
alpar@1
   133
//
alpar@1
   134
// This routine determines the value of non-basic variable xN[j] in the
alpar@1
   135
// current basic solution defined as follows:
alpar@1
   136
//
alpar@1
   137
//    0,             if xN[j] is free variable
alpar@1
   138
//    lN[j],         if xN[j] is on its lower bound
alpar@1
   139
//    uN[j],         if xN[j] is on its upper bound
alpar@1
   140
//    lN[j] = uN[j], if xN[j] is fixed variable
alpar@1
   141
//
alpar@1
   142
// where lN[j] and uN[j] are lower and upper bounds of xN[j]. */
alpar@1
   143
alpar@1
   144
void ssx_get_xNj(SSX *ssx, int j, mpq_t x)
alpar@1
   145
{     int m = ssx->m;
alpar@1
   146
      int n = ssx->n;
alpar@1
   147
      mpq_t *lb = ssx->lb;
alpar@1
   148
      mpq_t *ub = ssx->ub;
alpar@1
   149
      int *stat = ssx->stat;
alpar@1
   150
      int *Q_col = ssx->Q_col;
alpar@1
   151
      int k;
alpar@1
   152
      xassert(1 <= j && j <= n);
alpar@1
   153
      k = Q_col[m+j]; /* x[k] = xN[j] */
alpar@1
   154
      xassert(1 <= k && k <= m+n);
alpar@1
   155
      switch (stat[k])
alpar@1
   156
      {  case SSX_NL:
alpar@1
   157
            /* xN[j] is on its lower bound */
alpar@1
   158
            mpq_set(x, lb[k]); break;
alpar@1
   159
         case SSX_NU:
alpar@1
   160
            /* xN[j] is on its upper bound */
alpar@1
   161
            mpq_set(x, ub[k]); break;
alpar@1
   162
         case SSX_NF:
alpar@1
   163
            /* xN[j] is free variable */
alpar@1
   164
            mpq_set_si(x, 0, 1); break;
alpar@1
   165
         case SSX_NS:
alpar@1
   166
            /* xN[j] is fixed variable */
alpar@1
   167
            mpq_set(x, lb[k]); break;
alpar@1
   168
         default:
alpar@1
   169
            xassert(stat != stat);
alpar@1
   170
      }
alpar@1
   171
      return;
alpar@1
   172
}
alpar@1
   173
alpar@1
   174
/*----------------------------------------------------------------------
alpar@1
   175
// ssx_eval_bbar - compute values of basic variables.
alpar@1
   176
//
alpar@1
   177
// This routine computes values of basic variables xB in the current
alpar@1
   178
// basic solution as follows:
alpar@1
   179
//
alpar@1
   180
//    beta = - inv(B) * N * xN,
alpar@1
   181
//
alpar@1
   182
// where B is the basis matrix, N is the matrix of non-basic columns,
alpar@1
   183
// xN is a vector of current values of non-basic variables. */
alpar@1
   184
alpar@1
   185
void ssx_eval_bbar(SSX *ssx)
alpar@1
   186
{     int m = ssx->m;
alpar@1
   187
      int n = ssx->n;
alpar@1
   188
      mpq_t *coef = ssx->coef;
alpar@1
   189
      int *A_ptr = ssx->A_ptr;
alpar@1
   190
      int *A_ind = ssx->A_ind;
alpar@1
   191
      mpq_t *A_val = ssx->A_val;
alpar@1
   192
      int *Q_col = ssx->Q_col;
alpar@1
   193
      mpq_t *bbar = ssx->bbar;
alpar@1
   194
      int i, j, k, ptr;
alpar@1
   195
      mpq_t x, temp;
alpar@1
   196
      mpq_init(x);
alpar@1
   197
      mpq_init(temp);
alpar@1
   198
      /* bbar := 0 */
alpar@1
   199
      for (i = 1; i <= m; i++)
alpar@1
   200
         mpq_set_si(bbar[i], 0, 1);
alpar@1
   201
      /* bbar := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n] */
alpar@1
   202
      for (j = 1; j <= n; j++)
alpar@1
   203
      {  ssx_get_xNj(ssx, j, x);
alpar@1
   204
         if (mpq_sgn(x) == 0) continue;
alpar@1
   205
         k = Q_col[m+j]; /* x[k] = xN[j] */
alpar@1
   206
         if (k <= m)
alpar@1
   207
         {  /* N[j] is a column of the unity matrix I */
alpar@1
   208
            mpq_sub(bbar[k], bbar[k], x);
alpar@1
   209
         }
alpar@1
   210
         else
alpar@1
   211
         {  /* N[j] is a column of the original constraint matrix -A */
alpar@1
   212
            for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
alpar@1
   213
            {  mpq_mul(temp, A_val[ptr], x);
alpar@1
   214
               mpq_add(bbar[A_ind[ptr]], bbar[A_ind[ptr]], temp);
alpar@1
   215
            }
alpar@1
   216
         }
alpar@1
   217
      }
alpar@1
   218
      /* bbar := inv(B) * bbar */
alpar@1
   219
      bfx_ftran(ssx->binv, bbar, 0);
alpar@1
   220
#if 1
alpar@1
   221
      /* compute value of the objective function */
alpar@1
   222
      /* bbar[0] := c[0] */
alpar@1
   223
      mpq_set(bbar[0], coef[0]);
alpar@1
   224
      /* bbar[0] := bbar[0] + sum{i in B} cB[i] * xB[i] */
alpar@1
   225
      for (i = 1; i <= m; i++)
alpar@1
   226
      {  k = Q_col[i]; /* x[k] = xB[i] */
alpar@1
   227
         if (mpq_sgn(coef[k]) == 0) continue;
alpar@1
   228
         mpq_mul(temp, coef[k], bbar[i]);
alpar@1
   229
         mpq_add(bbar[0], bbar[0], temp);
alpar@1
   230
      }
alpar@1
   231
      /* bbar[0] := bbar[0] + sum{j in N} cN[j] * xN[j] */
alpar@1
   232
      for (j = 1; j <= n; j++)
alpar@1
   233
      {  k = Q_col[m+j]; /* x[k] = xN[j] */
alpar@1
   234
         if (mpq_sgn(coef[k]) == 0) continue;
alpar@1
   235
         ssx_get_xNj(ssx, j, x);
alpar@1
   236
         mpq_mul(temp, coef[k], x);
alpar@1
   237
         mpq_add(bbar[0], bbar[0], temp);
alpar@1
   238
      }
alpar@1
   239
#endif
alpar@1
   240
      mpq_clear(x);
alpar@1
   241
      mpq_clear(temp);
alpar@1
   242
      return;
alpar@1
   243
}
alpar@1
   244
alpar@1
   245
/*----------------------------------------------------------------------
alpar@1
   246
// ssx_eval_pi - compute values of simplex multipliers.
alpar@1
   247
//
alpar@1
   248
// This routine computes values of simplex multipliers (shadow prices)
alpar@1
   249
// pi in the current basic solution as follows:
alpar@1
   250
//
alpar@1
   251
//    pi = inv(B') * cB,
alpar@1
   252
//
alpar@1
   253
// where B' is a matrix transposed to the basis matrix B, cB is a vector
alpar@1
   254
// of objective coefficients at basic variables xB. */
alpar@1
   255
alpar@1
   256
void ssx_eval_pi(SSX *ssx)
alpar@1
   257
{     int m = ssx->m;
alpar@1
   258
      mpq_t *coef = ssx->coef;
alpar@1
   259
      int *Q_col = ssx->Q_col;
alpar@1
   260
      mpq_t *pi = ssx->pi;
alpar@1
   261
      int i;
alpar@1
   262
      /* pi := cB */
alpar@1
   263
      for (i = 1; i <= m; i++) mpq_set(pi[i], coef[Q_col[i]]);
alpar@1
   264
      /* pi := inv(B') * cB */
alpar@1
   265
      bfx_btran(ssx->binv, pi);
alpar@1
   266
      return;
alpar@1
   267
}
alpar@1
   268
alpar@1
   269
/*----------------------------------------------------------------------
alpar@1
   270
// ssx_eval_dj - compute reduced cost of non-basic variable.
alpar@1
   271
//
alpar@1
   272
// This routine computes reduced cost d[j] of non-basic variable xN[j]
alpar@1
   273
// in the current basic solution as follows:
alpar@1
   274
//
alpar@1
   275
//    d[j] = cN[j] - N[j] * pi,
alpar@1
   276
//
alpar@1
   277
// where cN[j] is an objective coefficient at xN[j], N[j] is a column
alpar@1
   278
// of the augmented constraint matrix (I | -A) corresponding to xN[j],
alpar@1
   279
// pi is the vector of simplex multipliers (shadow prices). */
alpar@1
   280
alpar@1
   281
void ssx_eval_dj(SSX *ssx, int j, mpq_t dj)
alpar@1
   282
{     int m = ssx->m;
alpar@1
   283
      int n = ssx->n;
alpar@1
   284
      mpq_t *coef = ssx->coef;
alpar@1
   285
      int *A_ptr = ssx->A_ptr;
alpar@1
   286
      int *A_ind = ssx->A_ind;
alpar@1
   287
      mpq_t *A_val = ssx->A_val;
alpar@1
   288
      int *Q_col = ssx->Q_col;
alpar@1
   289
      mpq_t *pi = ssx->pi;
alpar@1
   290
      int k, ptr, end;
alpar@1
   291
      mpq_t temp;
alpar@1
   292
      mpq_init(temp);
alpar@1
   293
      xassert(1 <= j && j <= n);
alpar@1
   294
      k = Q_col[m+j]; /* x[k] = xN[j] */
alpar@1
   295
      xassert(1 <= k && k <= m+n);
alpar@1
   296
      /* j-th column of the matrix N is k-th column of the augmented
alpar@1
   297
         constraint matrix (I | -A) */
alpar@1
   298
      if (k <= m)
alpar@1
   299
      {  /* it is a column of the unity matrix I */
alpar@1
   300
         mpq_sub(dj, coef[k], pi[k]);
alpar@1
   301
      }
alpar@1
   302
      else
alpar@1
   303
      {  /* it is a column of the original constraint matrix -A */
alpar@1
   304
         mpq_set(dj, coef[k]);
alpar@1
   305
         for (ptr = A_ptr[k-m], end = A_ptr[k-m+1]; ptr < end; ptr++)
alpar@1
   306
         {  mpq_mul(temp, A_val[ptr], pi[A_ind[ptr]]);
alpar@1
   307
            mpq_add(dj, dj, temp);
alpar@1
   308
         }
alpar@1
   309
      }
alpar@1
   310
      mpq_clear(temp);
alpar@1
   311
      return;
alpar@1
   312
}
alpar@1
   313
alpar@1
   314
/*----------------------------------------------------------------------
alpar@1
   315
// ssx_eval_cbar - compute reduced costs of all non-basic variables.
alpar@1
   316
//
alpar@1
   317
// This routine computes the vector of reduced costs pi in the current
alpar@1
   318
// basic solution for all non-basic variables, including fixed ones. */
alpar@1
   319
alpar@1
   320
void ssx_eval_cbar(SSX *ssx)
alpar@1
   321
{     int n = ssx->n;
alpar@1
   322
      mpq_t *cbar = ssx->cbar;
alpar@1
   323
      int j;
alpar@1
   324
      for (j = 1; j <= n; j++)
alpar@1
   325
         ssx_eval_dj(ssx, j, cbar[j]);
alpar@1
   326
      return;
alpar@1
   327
}
alpar@1
   328
alpar@1
   329
/*----------------------------------------------------------------------
alpar@1
   330
// ssx_eval_rho - compute p-th row of the inverse.
alpar@1
   331
//
alpar@1
   332
// This routine computes p-th row of the matrix inv(B), where B is the
alpar@1
   333
// current basis matrix.
alpar@1
   334
//
alpar@1
   335
// p-th row of the inverse is computed using the following formula:
alpar@1
   336
//
alpar@1
   337
//    rho = inv(B') * e[p],
alpar@1
   338
//
alpar@1
   339
// where B' is a matrix transposed to B, e[p] is a unity vector, which
alpar@1
   340
// contains one in p-th position. */
alpar@1
   341
alpar@1
   342
void ssx_eval_rho(SSX *ssx)
alpar@1
   343
{     int m = ssx->m;
alpar@1
   344
      int p = ssx->p;
alpar@1
   345
      mpq_t *rho = ssx->rho;
alpar@1
   346
      int i;
alpar@1
   347
      xassert(1 <= p && p <= m);
alpar@1
   348
      /* rho := 0 */
alpar@1
   349
      for (i = 1; i <= m; i++) mpq_set_si(rho[i], 0, 1);
alpar@1
   350
      /* rho := e[p] */
alpar@1
   351
      mpq_set_si(rho[p], 1, 1);
alpar@1
   352
      /* rho := inv(B') * rho */
alpar@1
   353
      bfx_btran(ssx->binv, rho);
alpar@1
   354
      return;
alpar@1
   355
}
alpar@1
   356
alpar@1
   357
/*----------------------------------------------------------------------
alpar@1
   358
// ssx_eval_row - compute pivot row of the simplex table.
alpar@1
   359
//
alpar@1
   360
// This routine computes p-th (pivot) row of the current simplex table
alpar@1
   361
// A~ = - inv(B) * N using the following formula:
alpar@1
   362
//
alpar@1
   363
//    A~[p] = - N' * inv(B') * e[p] = - N' * rho[p],
alpar@1
   364
//
alpar@1
   365
// where N' is a matrix transposed to the matrix N, rho[p] is p-th row
alpar@1
   366
// of the inverse inv(B). */
alpar@1
   367
alpar@1
   368
void ssx_eval_row(SSX *ssx)
alpar@1
   369
{     int m = ssx->m;
alpar@1
   370
      int n = ssx->n;
alpar@1
   371
      int *A_ptr = ssx->A_ptr;
alpar@1
   372
      int *A_ind = ssx->A_ind;
alpar@1
   373
      mpq_t *A_val = ssx->A_val;
alpar@1
   374
      int *Q_col = ssx->Q_col;
alpar@1
   375
      mpq_t *rho = ssx->rho;
alpar@1
   376
      mpq_t *ap = ssx->ap;
alpar@1
   377
      int j, k, ptr;
alpar@1
   378
      mpq_t temp;
alpar@1
   379
      mpq_init(temp);
alpar@1
   380
      for (j = 1; j <= n; j++)
alpar@1
   381
      {  /* ap[j] := - N'[j] * rho (inner product) */
alpar@1
   382
         k = Q_col[m+j]; /* x[k] = xN[j] */
alpar@1
   383
         if (k <= m)
alpar@1
   384
            mpq_neg(ap[j], rho[k]);
alpar@1
   385
         else
alpar@1
   386
         {  mpq_set_si(ap[j], 0, 1);
alpar@1
   387
            for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
alpar@1
   388
            {  mpq_mul(temp, A_val[ptr], rho[A_ind[ptr]]);
alpar@1
   389
               mpq_add(ap[j], ap[j], temp);
alpar@1
   390
            }
alpar@1
   391
         }
alpar@1
   392
      }
alpar@1
   393
      mpq_clear(temp);
alpar@1
   394
      return;
alpar@1
   395
}
alpar@1
   396
alpar@1
   397
/*----------------------------------------------------------------------
alpar@1
   398
// ssx_eval_col - compute pivot column of the simplex table.
alpar@1
   399
//
alpar@1
   400
// This routine computes q-th (pivot) column of the current simplex
alpar@1
   401
// table A~ = - inv(B) * N using the following formula:
alpar@1
   402
//
alpar@1
   403
//    A~[q] = - inv(B) * N[q],
alpar@1
   404
//
alpar@1
   405
// where N[q] is q-th column of the matrix N corresponding to chosen
alpar@1
   406
// non-basic variable xN[q]. */
alpar@1
   407
alpar@1
   408
void ssx_eval_col(SSX *ssx)
alpar@1
   409
{     int m = ssx->m;
alpar@1
   410
      int n = ssx->n;
alpar@1
   411
      int *A_ptr = ssx->A_ptr;
alpar@1
   412
      int *A_ind = ssx->A_ind;
alpar@1
   413
      mpq_t *A_val = ssx->A_val;
alpar@1
   414
      int *Q_col = ssx->Q_col;
alpar@1
   415
      int q = ssx->q;
alpar@1
   416
      mpq_t *aq = ssx->aq;
alpar@1
   417
      int i, k, ptr;
alpar@1
   418
      xassert(1 <= q && q <= n);
alpar@1
   419
      /* aq := 0 */
alpar@1
   420
      for (i = 1; i <= m; i++) mpq_set_si(aq[i], 0, 1);
alpar@1
   421
      /* aq := N[q] */
alpar@1
   422
      k = Q_col[m+q]; /* x[k] = xN[q] */
alpar@1
   423
      if (k <= m)
alpar@1
   424
      {  /* N[q] is a column of the unity matrix I */
alpar@1
   425
         mpq_set_si(aq[k], 1, 1);
alpar@1
   426
      }
alpar@1
   427
      else
alpar@1
   428
      {  /* N[q] is a column of the original constraint matrix -A */
alpar@1
   429
         for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
alpar@1
   430
            mpq_neg(aq[A_ind[ptr]], A_val[ptr]);
alpar@1
   431
      }
alpar@1
   432
      /* aq := inv(B) * aq */
alpar@1
   433
      bfx_ftran(ssx->binv, aq, 1);
alpar@1
   434
      /* aq := - aq */
alpar@1
   435
      for (i = 1; i <= m; i++) mpq_neg(aq[i], aq[i]);
alpar@1
   436
      return;
alpar@1
   437
}
alpar@1
   438
alpar@1
   439
/*----------------------------------------------------------------------
alpar@1
   440
// ssx_chuzc - choose pivot column.
alpar@1
   441
//
alpar@1
   442
// This routine chooses non-basic variable xN[q] whose reduced cost
alpar@1
   443
// indicates possible improving of the objective function to enter it
alpar@1
   444
// in the basis.
alpar@1
   445
//
alpar@1
   446
// Currently the standard (textbook) pricing is used, i.e. that
alpar@1
   447
// non-basic variable is preferred which has greatest reduced cost (in
alpar@1
   448
// magnitude).
alpar@1
   449
//
alpar@1
   450
// If xN[q] has been chosen, the routine stores its number q and also
alpar@1
   451
// sets the flag q_dir that indicates direction in which xN[q] has to
alpar@1
   452
// change (+1 means increasing, -1 means decreasing).
alpar@1
   453
//
alpar@1
   454
// If the choice cannot be made, because the current basic solution is
alpar@1
   455
// dual feasible, the routine sets the number q to 0. */
alpar@1
   456
alpar@1
   457
void ssx_chuzc(SSX *ssx)
alpar@1
   458
{     int m = ssx->m;
alpar@1
   459
      int n = ssx->n;
alpar@1
   460
      int dir = (ssx->dir == SSX_MIN ? +1 : -1);
alpar@1
   461
      int *Q_col = ssx->Q_col;
alpar@1
   462
      int *stat = ssx->stat;
alpar@1
   463
      mpq_t *cbar = ssx->cbar;
alpar@1
   464
      int j, k, s, q, q_dir;
alpar@1
   465
      double best, temp;
alpar@1
   466
      /* nothing is chosen so far */
alpar@1
   467
      q = 0, q_dir = 0, best = 0.0;
alpar@1
   468
      /* look through the list of non-basic variables */
alpar@1
   469
      for (j = 1; j <= n; j++)
alpar@1
   470
      {  k = Q_col[m+j]; /* x[k] = xN[j] */
alpar@1
   471
         s = dir * mpq_sgn(cbar[j]);
alpar@1
   472
         if ((stat[k] == SSX_NF || stat[k] == SSX_NL) && s < 0 ||
alpar@1
   473
             (stat[k] == SSX_NF || stat[k] == SSX_NU) && s > 0)
alpar@1
   474
         {  /* reduced cost of xN[j] indicates possible improving of
alpar@1
   475
               the objective function */
alpar@1
   476
            temp = fabs(mpq_get_d(cbar[j]));
alpar@1
   477
            xassert(temp != 0.0);
alpar@1
   478
            if (q == 0 || best < temp)
alpar@1
   479
               q = j, q_dir = - s, best = temp;
alpar@1
   480
         }
alpar@1
   481
      }
alpar@1
   482
      ssx->q = q, ssx->q_dir = q_dir;
alpar@1
   483
      return;
alpar@1
   484
}
alpar@1
   485
alpar@1
   486
/*----------------------------------------------------------------------
alpar@1
   487
// ssx_chuzr - choose pivot row.
alpar@1
   488
//
alpar@1
   489
// This routine looks through elements of q-th column of the simplex
alpar@1
   490
// table and chooses basic variable xB[p] which should leave the basis.
alpar@1
   491
//
alpar@1
   492
// The choice is based on the standard (textbook) ratio test.
alpar@1
   493
//
alpar@1
   494
// If xB[p] has been chosen, the routine stores its number p and also
alpar@1
   495
// sets its non-basic status p_stat which should be assigned to xB[p]
alpar@1
   496
// when it has left the basis and become xN[q].
alpar@1
   497
//
alpar@1
   498
// Special case p < 0 means that xN[q] is double-bounded variable and
alpar@1
   499
// it reaches its opposite bound before any basic variable does that,
alpar@1
   500
// so the current basis remains unchanged.
alpar@1
   501
//
alpar@1
   502
// If the choice cannot be made, because xN[q] can infinitely change in
alpar@1
   503
// the feasible direction, the routine sets the number p to 0. */
alpar@1
   504
alpar@1
   505
void ssx_chuzr(SSX *ssx)
alpar@1
   506
{     int m = ssx->m;
alpar@1
   507
      int n = ssx->n;
alpar@1
   508
      int *type = ssx->type;
alpar@1
   509
      mpq_t *lb = ssx->lb;
alpar@1
   510
      mpq_t *ub = ssx->ub;
alpar@1
   511
      int *Q_col = ssx->Q_col;
alpar@1
   512
      mpq_t *bbar = ssx->bbar;
alpar@1
   513
      int q = ssx->q;
alpar@1
   514
      mpq_t *aq = ssx->aq;
alpar@1
   515
      int q_dir = ssx->q_dir;
alpar@1
   516
      int i, k, s, t, p, p_stat;
alpar@1
   517
      mpq_t teta, temp;
alpar@1
   518
      mpq_init(teta);
alpar@1
   519
      mpq_init(temp);
alpar@1
   520
      xassert(1 <= q && q <= n);
alpar@1
   521
      xassert(q_dir == +1 || q_dir == -1);
alpar@1
   522
      /* nothing is chosen so far */
alpar@1
   523
      p = 0, p_stat = 0;
alpar@1
   524
      /* look through the list of basic variables */
alpar@1
   525
      for (i = 1; i <= m; i++)
alpar@1
   526
      {  s = q_dir * mpq_sgn(aq[i]);
alpar@1
   527
         if (s < 0)
alpar@1
   528
         {  /* xB[i] decreases */
alpar@1
   529
            k = Q_col[i]; /* x[k] = xB[i] */
alpar@1
   530
            t = type[k];
alpar@1
   531
            if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
alpar@1
   532
            {  /* xB[i] has finite lower bound */
alpar@1
   533
               mpq_sub(temp, bbar[i], lb[k]);
alpar@1
   534
               mpq_div(temp, temp, aq[i]);
alpar@1
   535
               mpq_abs(temp, temp);
alpar@1
   536
               if (p == 0 || mpq_cmp(teta, temp) > 0)
alpar@1
   537
               {  p = i;
alpar@1
   538
                  p_stat = (t == SSX_FX ? SSX_NS : SSX_NL);
alpar@1
   539
                  mpq_set(teta, temp);
alpar@1
   540
               }
alpar@1
   541
            }
alpar@1
   542
         }
alpar@1
   543
         else if (s > 0)
alpar@1
   544
         {  /* xB[i] increases */
alpar@1
   545
            k = Q_col[i]; /* x[k] = xB[i] */
alpar@1
   546
            t = type[k];
alpar@1
   547
            if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
alpar@1
   548
            {  /* xB[i] has finite upper bound */
alpar@1
   549
               mpq_sub(temp, bbar[i], ub[k]);
alpar@1
   550
               mpq_div(temp, temp, aq[i]);
alpar@1
   551
               mpq_abs(temp, temp);
alpar@1
   552
               if (p == 0 || mpq_cmp(teta, temp) > 0)
alpar@1
   553
               {  p = i;
alpar@1
   554
                  p_stat = (t == SSX_FX ? SSX_NS : SSX_NU);
alpar@1
   555
                  mpq_set(teta, temp);
alpar@1
   556
               }
alpar@1
   557
            }
alpar@1
   558
         }
alpar@1
   559
         /* if something has been chosen and the ratio test indicates
alpar@1
   560
            exact degeneracy, the search can be finished */
alpar@1
   561
         if (p != 0 && mpq_sgn(teta) == 0) break;
alpar@1
   562
      }
alpar@1
   563
      /* if xN[q] is double-bounded, check if it can reach its opposite
alpar@1
   564
         bound before any basic variable */
alpar@1
   565
      k = Q_col[m+q]; /* x[k] = xN[q] */
alpar@1
   566
      if (type[k] == SSX_DB)
alpar@1
   567
      {  mpq_sub(temp, ub[k], lb[k]);
alpar@1
   568
         if (p == 0 || mpq_cmp(teta, temp) > 0)
alpar@1
   569
         {  p = -1;
alpar@1
   570
            p_stat = -1;
alpar@1
   571
            mpq_set(teta, temp);
alpar@1
   572
         }
alpar@1
   573
      }
alpar@1
   574
      ssx->p = p;
alpar@1
   575
      ssx->p_stat = p_stat;
alpar@1
   576
      /* if xB[p] has been chosen, determine its actual change in the
alpar@1
   577
         adjacent basis (it has the same sign as q_dir) */
alpar@1
   578
      if (p != 0)
alpar@1
   579
      {  xassert(mpq_sgn(teta) >= 0);
alpar@1
   580
         if (q_dir > 0)
alpar@1
   581
            mpq_set(ssx->delta, teta);
alpar@1
   582
         else
alpar@1
   583
            mpq_neg(ssx->delta, teta);
alpar@1
   584
      }
alpar@1
   585
      mpq_clear(teta);
alpar@1
   586
      mpq_clear(temp);
alpar@1
   587
      return;
alpar@1
   588
}
alpar@1
   589
alpar@1
   590
/*----------------------------------------------------------------------
alpar@1
   591
// ssx_update_bbar - update values of basic variables.
alpar@1
   592
//
alpar@1
   593
// This routine recomputes the current values of basic variables for
alpar@1
   594
// the adjacent basis.
alpar@1
   595
//
alpar@1
   596
// The simplex table for the current basis is the following:
alpar@1
   597
//
alpar@1
   598
//    xB[i] = sum{j in 1..n} alfa[i,j] * xN[q],  i = 1,...,m
alpar@1
   599
//
alpar@1
   600
// therefore
alpar@1
   601
//
alpar@1
   602
//    delta xB[i] = alfa[i,q] * delta xN[q],  i = 1,...,m
alpar@1
   603
//
alpar@1
   604
// where delta xN[q] = xN.new[q] - xN[q] is the change of xN[q] in the
alpar@1
   605
// adjacent basis, and delta xB[i] = xB.new[i] - xB[i] is the change of
alpar@1
   606
// xB[i]. This gives formulae for recomputing values of xB[i]:
alpar@1
   607
//
alpar@1
   608
//    xB.new[p] = xN[q] + delta xN[q]
alpar@1
   609
//
alpar@1
   610
// (because xN[q] becomes xB[p] in the adjacent basis), and
alpar@1
   611
//
alpar@1
   612
//    xB.new[i] = xB[i] + alfa[i,q] * delta xN[q],  i != p
alpar@1
   613
//
alpar@1
   614
// for other basic variables. */
alpar@1
   615
alpar@1
   616
void ssx_update_bbar(SSX *ssx)
alpar@1
   617
{     int m = ssx->m;
alpar@1
   618
      int n = ssx->n;
alpar@1
   619
      mpq_t *bbar = ssx->bbar;
alpar@1
   620
      mpq_t *cbar = ssx->cbar;
alpar@1
   621
      int p = ssx->p;
alpar@1
   622
      int q = ssx->q;
alpar@1
   623
      mpq_t *aq = ssx->aq;
alpar@1
   624
      int i;
alpar@1
   625
      mpq_t temp;
alpar@1
   626
      mpq_init(temp);
alpar@1
   627
      xassert(1 <= q && q <= n);
alpar@1
   628
      if (p < 0)
alpar@1
   629
      {  /* xN[q] is double-bounded and goes to its opposite bound */
alpar@1
   630
         /* nop */;
alpar@1
   631
      }
alpar@1
   632
      else
alpar@1
   633
      {  /* xN[q] becomes xB[p] in the adjacent basis */
alpar@1
   634
         /* xB.new[p] = xN[q] + delta xN[q] */
alpar@1
   635
         xassert(1 <= p && p <= m);
alpar@1
   636
         ssx_get_xNj(ssx, q, temp);
alpar@1
   637
         mpq_add(bbar[p], temp, ssx->delta);
alpar@1
   638
      }
alpar@1
   639
      /* update values of other basic variables depending on xN[q] */
alpar@1
   640
      for (i = 1; i <= m; i++)
alpar@1
   641
      {  if (i == p) continue;
alpar@1
   642
         /* xB.new[i] = xB[i] + alfa[i,q] * delta xN[q] */
alpar@1
   643
         if (mpq_sgn(aq[i]) == 0) continue;
alpar@1
   644
         mpq_mul(temp, aq[i], ssx->delta);
alpar@1
   645
         mpq_add(bbar[i], bbar[i], temp);
alpar@1
   646
      }
alpar@1
   647
#if 1
alpar@1
   648
      /* update value of the objective function */
alpar@1
   649
      /* z.new = z + d[q] * delta xN[q] */
alpar@1
   650
      mpq_mul(temp, cbar[q], ssx->delta);
alpar@1
   651
      mpq_add(bbar[0], bbar[0], temp);
alpar@1
   652
#endif
alpar@1
   653
      mpq_clear(temp);
alpar@1
   654
      return;
alpar@1
   655
}
alpar@1
   656
alpar@1
   657
/*----------------------------------------------------------------------
alpar@1
   658
-- ssx_update_pi - update simplex multipliers.
alpar@1
   659
--
alpar@1
   660
-- This routine recomputes the vector of simplex multipliers for the
alpar@1
   661
-- adjacent basis. */
alpar@1
   662
alpar@1
   663
void ssx_update_pi(SSX *ssx)
alpar@1
   664
{     int m = ssx->m;
alpar@1
   665
      int n = ssx->n;
alpar@1
   666
      mpq_t *pi = ssx->pi;
alpar@1
   667
      mpq_t *cbar = ssx->cbar;
alpar@1
   668
      int p = ssx->p;
alpar@1
   669
      int q = ssx->q;
alpar@1
   670
      mpq_t *aq = ssx->aq;
alpar@1
   671
      mpq_t *rho = ssx->rho;
alpar@1
   672
      int i;
alpar@1
   673
      mpq_t new_dq, temp;
alpar@1
   674
      mpq_init(new_dq);
alpar@1
   675
      mpq_init(temp);
alpar@1
   676
      xassert(1 <= p && p <= m);
alpar@1
   677
      xassert(1 <= q && q <= n);
alpar@1
   678
      /* compute d[q] in the adjacent basis */
alpar@1
   679
      mpq_div(new_dq, cbar[q], aq[p]);
alpar@1
   680
      /* update the vector of simplex multipliers */
alpar@1
   681
      for (i = 1; i <= m; i++)
alpar@1
   682
      {  if (mpq_sgn(rho[i]) == 0) continue;
alpar@1
   683
         mpq_mul(temp, new_dq, rho[i]);
alpar@1
   684
         mpq_sub(pi[i], pi[i], temp);
alpar@1
   685
      }
alpar@1
   686
      mpq_clear(new_dq);
alpar@1
   687
      mpq_clear(temp);
alpar@1
   688
      return;
alpar@1
   689
}
alpar@1
   690
alpar@1
   691
/*----------------------------------------------------------------------
alpar@1
   692
// ssx_update_cbar - update reduced costs of non-basic variables.
alpar@1
   693
//
alpar@1
   694
// This routine recomputes the vector of reduced costs of non-basic
alpar@1
   695
// variables for the adjacent basis. */
alpar@1
   696
alpar@1
   697
void ssx_update_cbar(SSX *ssx)
alpar@1
   698
{     int m = ssx->m;
alpar@1
   699
      int n = ssx->n;
alpar@1
   700
      mpq_t *cbar = ssx->cbar;
alpar@1
   701
      int p = ssx->p;
alpar@1
   702
      int q = ssx->q;
alpar@1
   703
      mpq_t *ap = ssx->ap;
alpar@1
   704
      int j;
alpar@1
   705
      mpq_t temp;
alpar@1
   706
      mpq_init(temp);
alpar@1
   707
      xassert(1 <= p && p <= m);
alpar@1
   708
      xassert(1 <= q && q <= n);
alpar@1
   709
      /* compute d[q] in the adjacent basis */
alpar@1
   710
      /* d.new[q] = d[q] / alfa[p,q] */
alpar@1
   711
      mpq_div(cbar[q], cbar[q], ap[q]);
alpar@1
   712
      /* update reduced costs of other non-basic variables */
alpar@1
   713
      for (j = 1; j <= n; j++)
alpar@1
   714
      {  if (j == q) continue;
alpar@1
   715
         /* d.new[j] = d[j] - (alfa[p,j] / alfa[p,q]) * d[q] */
alpar@1
   716
         if (mpq_sgn(ap[j]) == 0) continue;
alpar@1
   717
         mpq_mul(temp, ap[j], cbar[q]);
alpar@1
   718
         mpq_sub(cbar[j], cbar[j], temp);
alpar@1
   719
      }
alpar@1
   720
      mpq_clear(temp);
alpar@1
   721
      return;
alpar@1
   722
}
alpar@1
   723
alpar@1
   724
/*----------------------------------------------------------------------
alpar@1
   725
// ssx_change_basis - change current basis to adjacent one.
alpar@1
   726
//
alpar@1
   727
// This routine changes the current basis to the adjacent one swapping
alpar@1
   728
// basic variable xB[p] and non-basic variable xN[q]. */
alpar@1
   729
alpar@1
   730
void ssx_change_basis(SSX *ssx)
alpar@1
   731
{     int m = ssx->m;
alpar@1
   732
      int n = ssx->n;
alpar@1
   733
      int *type = ssx->type;
alpar@1
   734
      int *stat = ssx->stat;
alpar@1
   735
      int *Q_row = ssx->Q_row;
alpar@1
   736
      int *Q_col = ssx->Q_col;
alpar@1
   737
      int p = ssx->p;
alpar@1
   738
      int q = ssx->q;
alpar@1
   739
      int p_stat = ssx->p_stat;
alpar@1
   740
      int k, kp, kq;
alpar@1
   741
      if (p < 0)
alpar@1
   742
      {  /* special case: xN[q] goes to its opposite bound */
alpar@1
   743
         xassert(1 <= q && q <= n);
alpar@1
   744
         k = Q_col[m+q]; /* x[k] = xN[q] */
alpar@1
   745
         xassert(type[k] == SSX_DB);
alpar@1
   746
         switch (stat[k])
alpar@1
   747
         {  case SSX_NL:
alpar@1
   748
               stat[k] = SSX_NU;
alpar@1
   749
               break;
alpar@1
   750
            case SSX_NU:
alpar@1
   751
               stat[k] = SSX_NL;
alpar@1
   752
               break;
alpar@1
   753
            default:
alpar@1
   754
               xassert(stat != stat);
alpar@1
   755
         }
alpar@1
   756
      }
alpar@1
   757
      else
alpar@1
   758
      {  /* xB[p] leaves the basis, xN[q] enters the basis */
alpar@1
   759
         xassert(1 <= p && p <= m);
alpar@1
   760
         xassert(1 <= q && q <= n);
alpar@1
   761
         kp = Q_col[p];   /* x[kp] = xB[p] */
alpar@1
   762
         kq = Q_col[m+q]; /* x[kq] = xN[q] */
alpar@1
   763
         /* check non-basic status of xB[p] which becomes xN[q] */
alpar@1
   764
         switch (type[kp])
alpar@1
   765
         {  case SSX_FR:
alpar@1
   766
               xassert(p_stat == SSX_NF);
alpar@1
   767
               break;
alpar@1
   768
            case SSX_LO:
alpar@1
   769
               xassert(p_stat == SSX_NL);
alpar@1
   770
               break;
alpar@1
   771
            case SSX_UP:
alpar@1
   772
               xassert(p_stat == SSX_NU);
alpar@1
   773
               break;
alpar@1
   774
            case SSX_DB:
alpar@1
   775
               xassert(p_stat == SSX_NL || p_stat == SSX_NU);
alpar@1
   776
               break;
alpar@1
   777
            case SSX_FX:
alpar@1
   778
               xassert(p_stat == SSX_NS);
alpar@1
   779
               break;
alpar@1
   780
            default:
alpar@1
   781
               xassert(type != type);
alpar@1
   782
         }
alpar@1
   783
         /* swap xB[p] and xN[q] */
alpar@1
   784
         stat[kp] = (char)p_stat, stat[kq] = SSX_BS;
alpar@1
   785
         Q_row[kp] = m+q, Q_row[kq] = p;
alpar@1
   786
         Q_col[p] = kq, Q_col[m+q] = kp;
alpar@1
   787
         /* update factorization of the basis matrix */
alpar@1
   788
         if (bfx_update(ssx->binv, p))
alpar@1
   789
         {  if (ssx_factorize(ssx))
alpar@1
   790
               xassert(("Internal error: basis matrix is singular", 0));
alpar@1
   791
         }
alpar@1
   792
      }
alpar@1
   793
      return;
alpar@1
   794
}
alpar@1
   795
alpar@1
   796
/*----------------------------------------------------------------------
alpar@1
   797
// ssx_delete - delete simplex solver workspace.
alpar@1
   798
//
alpar@1
   799
// This routine deletes the simplex solver workspace freeing all the
alpar@1
   800
// memory allocated to this object. */
alpar@1
   801
alpar@1
   802
void ssx_delete(SSX *ssx)
alpar@1
   803
{     int m = ssx->m;
alpar@1
   804
      int n = ssx->n;
alpar@1
   805
      int nnz = ssx->A_ptr[n+1]-1;
alpar@1
   806
      int i, j, k;
alpar@1
   807
      xfree(ssx->type);
alpar@1
   808
      for (k = 1; k <= m+n; k++) mpq_clear(ssx->lb[k]);
alpar@1
   809
      xfree(ssx->lb);
alpar@1
   810
      for (k = 1; k <= m+n; k++) mpq_clear(ssx->ub[k]);
alpar@1
   811
      xfree(ssx->ub);
alpar@1
   812
      for (k = 0; k <= m+n; k++) mpq_clear(ssx->coef[k]);
alpar@1
   813
      xfree(ssx->coef);
alpar@1
   814
      xfree(ssx->A_ptr);
alpar@1
   815
      xfree(ssx->A_ind);
alpar@1
   816
      for (k = 1; k <= nnz; k++) mpq_clear(ssx->A_val[k]);
alpar@1
   817
      xfree(ssx->A_val);
alpar@1
   818
      xfree(ssx->stat);
alpar@1
   819
      xfree(ssx->Q_row);
alpar@1
   820
      xfree(ssx->Q_col);
alpar@1
   821
      bfx_delete_binv(ssx->binv);
alpar@1
   822
      for (i = 0; i <= m; i++) mpq_clear(ssx->bbar[i]);
alpar@1
   823
      xfree(ssx->bbar);
alpar@1
   824
      for (i = 1; i <= m; i++) mpq_clear(ssx->pi[i]);
alpar@1
   825
      xfree(ssx->pi);
alpar@1
   826
      for (j = 1; j <= n; j++) mpq_clear(ssx->cbar[j]);
alpar@1
   827
      xfree(ssx->cbar);
alpar@1
   828
      for (i = 1; i <= m; i++) mpq_clear(ssx->rho[i]);
alpar@1
   829
      xfree(ssx->rho);
alpar@1
   830
      for (j = 1; j <= n; j++) mpq_clear(ssx->ap[j]);
alpar@1
   831
      xfree(ssx->ap);
alpar@1
   832
      for (i = 1; i <= m; i++) mpq_clear(ssx->aq[i]);
alpar@1
   833
      xfree(ssx->aq);
alpar@1
   834
      mpq_clear(ssx->delta);
alpar@1
   835
      xfree(ssx);
alpar@1
   836
      return;
alpar@1
   837
}
alpar@1
   838
alpar@1
   839
/* eof */