source: branches/devel-1/PresolveSubst.cpp @ 2351

Last change on this file since 2351 was 49, checked in by ladanyi, 17 years ago

everything compiles

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.3 KB
Line 
1#include <stdio.h>
2#include <math.h>
3#include <strings.h>
4
5#include "PresolveMatrix.hpp"
6#include "PresolveEmpty.hpp"    // for DROP_COL/DROP_ROW
7#include "PresolveFixed.hpp"
8#include "PresolveZeros.hpp"
9#include "PresolveSubst.hpp"
10#include "ClpMessage.hpp"
11#include "CoinSort.hpp"
12
13inline void prepend_elem(int jcol, double coeff, int irow,
14                    CoinBigIndex *mcstrt,
15                    double *colels,
16                    int *hrow,
17                    int *link, CoinBigIndex *free_listp)
18{
19  CoinBigIndex kk = *free_listp;
20  *free_listp = link[*free_listp];
21  check_free_list(*free_listp);
22
23  link[kk] = mcstrt[jcol];
24  mcstrt[jcol] = kk;
25  colels[kk] = coeff;
26  hrow[kk] = irow;
27}
28
29const char *subst_constraint_action::name() const
30{
31  return ("subst_constraint_action");
32}
33
34void compact_rep(double *elems, int *indices, CoinBigIndex *starts, const int *lengths, int n,
35                 const presolvehlink *link);
36
37inline int min(int x, int y)
38{
39  return (x < y) ? x : y;
40}
41
42
43// copy of expand_col; have to rename params
44static void expand_row(CoinBigIndex *mcstrt, 
45                    double *colels,
46                       int *hrow, // int *hcol,
47                       //int *hinrow,
48                       int *hincol,
49                    presolvehlink *clink, int ncols,
50
51                       int icolx
52                       ///, int icoly
53                       )
54{
55  /////CoinBigIndex kcs = mcstrt[icoly];
56  /////CoinBigIndex kce = kcs + hincol[icoly];
57  CoinBigIndex kcsx = mcstrt[icolx];
58  CoinBigIndex kcex = kcsx + hincol[icolx];
59
60  const int maxk = mcstrt[ncols];       // (22)
61
62  // update col rep - need to expand the column, though.
63  int nextcol = clink[icolx].suc;
64
65  // (22)
66  if (kcex + 1 < mcstrt[nextcol] || nextcol == ncols) {
67    if (! (kcex + 1 < mcstrt[nextcol])) {
68      // nextcol==ncols and no space - must compact
69      compact_rep(colels, hrow, mcstrt, hincol, ncols, clink);
70
71      // update vars
72      kcsx = mcstrt[icolx];
73      kcex = kcsx + hincol[icolx];
74
75      if (! (kcex + 1 < mcstrt[nextcol])) {
76        abort();
77      }
78    }
79  } else {
80    // this is not the last col
81    // fetch last non-empty col (presolve_make_memlists-1)
82    int lastcol = clink[ncols].pre;
83    // (clink[icolx].suc != ncols) ==> (icolx != lastcol)
84
85    // put it directly after the last column
86    int newkcsx = mcstrt[lastcol] + hincol[lastcol];
87
88    // well, pad it a bit
89    newkcsx += min(hincol[icolx], 5); // slack
90
91    //printf("EXPAND_ROW:  %d %d %d\n", newkcsx, maxk, icolx);
92
93    if (newkcsx + hincol[icolx] + 1 >= maxk) {
94      compact_rep(colels, hrow, mcstrt, hincol, ncols, clink);
95
96      // update vars
97      kcsx = mcstrt[icolx];
98      kcex = kcsx + hincol[icolx];
99
100      newkcsx = mcstrt[lastcol] + hincol[lastcol];
101
102      if (newkcsx + hincol[icolx] + 1 >= maxk) {
103        abort();
104      }
105      // have to adjust various induction variables
106      ////kcoly = mcstrt[icoly] + (kcoly - kcs);
107      /////kcs = mcstrt[icoly];                 // do this for ease of debugging
108      /////kce = mcstrt[icoly] + hincol[icoly];
109           
110      /////kcolx = mcstrt[icolx] + (kcolx - kcs);       // don't really need to do this
111      kcsx = mcstrt[icolx];
112      kcex = mcstrt[icolx] + hincol[icolx];
113    }
114
115    // move the column - 1:  copy the entries
116    bcopy((void*)&hrow[kcsx], (void*)&hrow[newkcsx], hincol[icolx] * sizeof(int));
117    bcopy((void*)&colels[kcsx], (void*)&colels[newkcsx], hincol[icolx] * sizeof(double));
118
119    // move the column - 2:  update the memory-order linked list
120    PRESOLVE_REMOVE_LINK(clink, icolx);
121    PRESOLVE_INSERT_LINK(clink, icolx, lastcol);
122
123    // move the column - 3:  update loop variables to maintain invariant
124    mcstrt[icolx] = newkcsx;
125    kcsx = newkcsx;
126    kcex = newkcsx + hincol[icolx];
127
128#if 0
129    hincol[icolx]++;
130    kcex = newkcsx + hincol[icolx];
131
132    // move the column - 4:  add the new entry
133    hrow[kcex-1] = row;
134    colels[kcex-1] = colels[kcoly] * coeff_factor;
135#endif
136  }
137}
138
139// add coeff_factor * rowy to rowx
140void add_row(CoinBigIndex *mrstrt, 
141             double *rlo, double * acts, double *rup,
142             double *rowels,
143             int *hcol,
144             int *hinrow,
145             presolvehlink *rlink, int nrows,
146             double coeff_factor,
147             int irowx, int irowy,
148             int *x_to_y)
149{
150  CoinBigIndex krs = mrstrt[irowy];
151  CoinBigIndex kre = krs + hinrow[irowy];
152  CoinBigIndex krsx = mrstrt[irowx];
153  CoinBigIndex krex = krsx + hinrow[irowx];
154  //  const int maxk = mrstrt[nrows];   // (22)
155
156  // if irowx is very long, the searching gets very slow,
157  // so we always sort.
158  // whatever sorts rows should handle almost-sorted data efficiently
159  // (quicksort may not)
160  CoinSort_2(hcol+krsx,hcol+krsx+hinrow[irowx],rowels+krsx);
161  CoinSort_2(hcol+krs,hcol+krs+hinrow[irowy],rowels+krs);
162  //ekk_sort2(hcol+krsx, rowels+krsx, hinrow[irowx]);
163  //ekk_sort2(hcol+krs,  rowels+krs,  hinrow[irowy]);
164
165  //printf("%s x=%d y=%d cf=%g nx=%d ny=%d\n",
166  // "ADD_ROW:",
167  //  irowx, irowy, coeff_factor, hinrow[irowx], hinrow[irowy]);
168
169#if     DEBUG_PRESOLVE
170  printf("%s x=%d y=%d cf=%g nx=%d ycols=(",
171         "ADD_ROW:",
172          irowx, irowy, coeff_factor, hinrow[irowx]);
173#endif
174
175  // adjust row bounds of rowx;
176  // analogous to adjusting bounds info of colx in doubleton,
177  // or perhaps adjustment to rlo/rup in elim_doubleton
178  //
179  // I believe that since we choose a column that is implied free,
180  // no other column bounds need to be updated.
181  // This is what would happen in doubleton if y's bounds were implied free;
182  // in that case,
183  // lo1 would never improve clo[icolx] and
184  // up1 would never improve cup[icolx].
185  {
186    double rhsy = rlo[irowy];
187
188    // (1)
189    if (-PRESOLVE_INF < rlo[irowx]) {
190#if     DEBUG_PRESOLVE
191      if (rhsy * coeff_factor)
192        printf("ELIM_ROW RLO:  %g -> %g\n",
193               rlo[irowx],
194               rlo[irowx] + rhsy * coeff_factor);
195#endif
196      rlo[irowx] += rhsy * coeff_factor;
197    }
198    // (2)
199    if (rup[irowx] < PRESOLVE_INF) {
200#if     DEBUG_PRESOLVE
201      if (rhsy * coeff_factor)
202        printf("ELIM_ROW RUP:  %g -> %g\n",
203               rup[irowx],
204               rup[irowx] + rhsy * coeff_factor);
205#endif
206      rup[irowx] += rhsy * coeff_factor;
207    }
208    acts[irowx] += rhsy * coeff_factor;
209  }
210
211  CoinBigIndex kcolx = krsx;
212  CoinBigIndex krex0 = krex;
213  int x_to_y_i = 0;
214
215  for (CoinBigIndex krowy=krs; krowy<kre; krowy++) {
216    int jcol = hcol[krowy];
217
218    // even though these values are updated, they remain consistent
219    PRESOLVEASSERT(krex == krsx + hinrow[irowx]);
220
221    // see if row appears in colx
222    // do NOT look beyond the original elements of rowx
223    //CoinBigIndex kcolx = presolve_find_row1(jcol, krsx, krex, hcol);
224    while (kcolx < krex0 && hcol[kcolx] < jcol)
225      kcolx++;
226
227#if     DEBUG_PRESOLVE
228    printf("%d%s ", jcol, (kcolx < krex0 && hcol[kcolx] == jcol) ? "+" : "");
229#endif
230
231    if (kcolx < krex0 && hcol[kcolx] == jcol) {
232      // before:  both x and y are in the jcol
233      // after:   only x is in the jcol
234      // so: number of elems in col x unchanged, and num elems in jcol is one less
235
236      // update row rep - just modify coefficent
237      // column y is deleted as a whole at the end of the loop
238#if     DEBUG_PRESOLVE
239      printf("CHANGING %g + %g -> %g\n",
240             rowels[kcolx],
241             rowels[krowy],
242             rowels[kcolx] + rowels[krowy] * coeff_factor);
243#endif
244      rowels[kcolx] += rowels[krowy] * coeff_factor;
245
246      // this is where this element in rowy ended up
247      x_to_y[x_to_y_i++] = kcolx - krsx;
248      kcolx++;
249    } else {
250      // before:  only y is in the jcol
251      // after:   only x is in the jcol
252      // so: number of elems in col x is one greater, but num elems in jcol remains same
253      {
254        expand_row(mrstrt, rowels, hcol, hinrow, rlink, nrows, irowx);
255        // this may force a compaction
256        // this will be called excessively if the rows are packed too tightly
257
258        // have to adjust various induction variables
259        krowy = mrstrt[irowy] + (krowy - krs);
260        krs = mrstrt[irowy];                    // do this for ease of debugging
261        kre = mrstrt[irowy] + hinrow[irowy];
262           
263        kcolx = mrstrt[irowx] + (kcolx - krsx); // don't really need to do this
264        krex0 = mrstrt[irowx] + (krex0 - krsx);
265        krsx = mrstrt[irowx];
266        krex = mrstrt[irowx] + hinrow[irowx];
267      }
268
269      // this is where this element in rowy ended up
270      x_to_y[x_to_y_i++] = krex - krsx;
271
272      // there is now an unused entry in the memory after the column - use it
273      // mrstrt[nrows] == penultimate index of arrays hcol/rowels
274      hcol[krex] = jcol;
275      rowels[krex] = rowels[krowy] * coeff_factor;
276      hinrow[irowx]++, krex++;  // expand the col
277
278      // do NOT increment kcolx
279    }
280  }
281
282#if     DEBUG_PRESOLVE
283  printf(")\n");
284#endif
285}
286
287
288// It is common in osl to copy from one representation to another
289// (say from a col rep to a row rep).
290// One such routine is ekkclcp.
291// This is similar, except that it does not assume that the
292// representation is packed, and it adds some slack space
293// in the target rep.
294// It assumes both hincol/hinrow are correct.
295// Note that such routines automatically sort the target rep by index,
296// because they sweep the rows in ascending order.
297void copyrep(const int * mrstrt, const int *hcol, const double *rowels, 
298             const int *hinrow, int nrows,
299             int *mcstrt, int *hrow, double *colels, 
300             int *hincol, int ncols)
301{
302  int pos = 0;
303  for (int j = 0; j < ncols; ++j) {
304    mcstrt[j] = pos;
305    pos += hincol[j];
306    pos += min(hincol[j], 10); // slack
307    hincol[j] = 0;
308  }
309
310  for (int i = 0; i < nrows; ++i) {
311    CoinBigIndex krs = mrstrt[i];
312    CoinBigIndex kre = krs + hinrow[i];
313    for (CoinBigIndex kr = krs; kr < kre; ++kr) {
314      int icol = hcol[kr];
315      int iput = hincol[icol];
316      hincol[icol] = iput + 1;
317      iput += mcstrt[icol];
318     
319      hrow[iput] = i;
320      colels[iput] = rowels[kr];
321    }
322  }
323}
324
325#if 0
326// variant of function of same name in ekk_7.c
327// exactly the same, with some code #if'ed out
328int ekk_makeColumnOrdered(int * indexRow , int * indexColumn , double * element ,
329                          int * rowCount , int * columnCount , CoinBigIndex * startColumn ,
330                          int numberRows , int numberColumns,
331                          CoinBigIndex numberElements, double tolerance)
332{
333  int iColumn,i,k;
334#if 0
335  for (i=0;i<numberRows;i++) {
336    rowCount[i]=0;
337  }
338  for (i=0;i<numberColumns;i++) {
339    columnCount[i]=0;
340  }
341  for (i=0;i<numberElements;i++) {
342    int iRow=indexRow[i];
343    int iColumn=indexColumn[i];
344    rowCount[iRow]++;
345    columnCount[iColumn]++;
346  }
347#endif
348
349  i=0;
350  for (iColumn=0;iColumn<numberColumns;iColumn++) {
351    /* position after end of Column */
352    i+=columnCount[iColumn];
353    startColumn[iColumn]=i;
354  } /* endfor */
355  startColumn[iColumn]=i;
356
357  for (k=numberElements-1;k>=0;k--) {
358    iColumn=indexColumn[k];
359    if (iColumn>=0) {
360      /* pick up the entry with your right hand */
361      double value = element[k];
362      int iRow=indexRow[k];
363      int iColumnSave=0;
364      indexColumn[k]=-2;        /* the hole */
365
366      while (1) {
367        /* pick this up with your left */
368        int iLook=startColumn[iColumn]-1;
369        double valueSave=element[iLook];
370        int iColumnSave=indexColumn[iLook];
371        int iRowSave=indexRow[iLook];
372
373        /* put the right-hand entry where it wanted to go */
374        startColumn[iColumn]=iLook;
375        element[iLook]=value;
376        indexRow[iLook]=iRow;
377        indexColumn[iLook]=-1;  /* mark it as being where it wants to be */
378       
379        /* there was something there */
380        if (iColumnSave>=0) {
381          iColumn=iColumnSave;
382          value=valueSave;
383          iRow=iRowSave;
384        } else if (iColumnSave = -2)    /* that was the hole */
385          break;
386        else
387          ekkmesg_no(158);      /* should never happen */
388        /* endif */
389      } /* endwhile */
390    } /* endif */
391  } /* endfor */
392
393#if 0
394  /* now pack the elements and combine entries with the same row and column */
395  /* also, drop entries with "small" coefficients */
396  numberElements=0;
397  for (iColumn=0;iColumn<numberColumns;iColumn++) {
398    CoinBigIndex start=startColumn[iColumn];
399    CoinBigIndex end =startColumn[iColumn+1];
400    startColumn[iColumn]=numberElements;
401    if (end>start) {
402      int lastRow;
403      double lastValue;
404      CoinSort_2(indexRow+start,indexRow+end,element+start);
405      //ekk_sort2(indexRow+start,element+start,end-start);
406      lastRow=indexRow[start];
407      lastValue=element[start];
408      for (i=start+1;i<end;i++) {
409        int iRow=indexRow[i];
410        double value=element[i];
411        if (iRow>lastRow) {
412          if(fabs(lastValue)>tolerance) {
413            indexRow[numberElements]=lastRow;
414            element[numberElements]=lastValue;
415            numberElements++;
416          }
417          lastRow=iRow;
418          lastValue=value;
419        } else {
420          lastValue+=value;
421        } /* endif */
422      } /* endfor */
423      if(fabs(lastValue)>tolerance) {
424        indexRow[numberElements]=lastRow;
425        element[numberElements]=lastValue;
426        numberElements++;
427      }
428    }
429  } /* endfor */
430#endif
431
432  startColumn[numberColumns]=numberElements;
433  return numberElements;
434}
435#endif
436
437
438// add -x/y times row y to row x, thus cancelling out one column of rowx;
439// afterwards, that col will be singleton for rowy, so we drop the row.
440//
441// This no longer maintains the col rep as it goes along.
442// Instead, it reconstructs it from scratch afterward.
443//
444// This implements the functionality of ekkrdc3.
445const PresolveAction *subst_constraint_action::presolve(PresolveMatrix *prob,
446                                         char *implied_free,
447                                        const PresolveAction *next,
448                                                        int &try_fill_level)
449{
450  double *colels        = prob->colels_;
451  int *hrow     = prob->hrow_;
452  CoinBigIndex *mcstrt  = prob->mcstrt_;
453  int *hincol   = prob->hincol_;
454  const int ncols       = prob->ncols_;
455
456  const double *clo     = prob->clo_;
457  const double *cup     = prob->cup_;
458
459  double *rowels        = prob->rowels_;
460  int *hcol     = prob->hcol_;
461  CoinBigIndex *mrstrt  = prob->mrstrt_;
462  int *hinrow   = prob->hinrow_;
463  const int nrows       = prob->nrows_;
464
465  double *rlo   = prob->rlo_;
466  double *rup   = prob->rup_;
467  double *acts  = prob->acts_;
468
469  double *dcost         = prob->cost_;
470
471  presolvehlink *clink = prob->clink_;
472  presolvehlink *rlink = prob->rlink_;
473
474  const double tol = prob->feasibilityTolerance_;
475
476  action *actions       = new action [ncols];
477  int nactions = 0;
478
479  int *zerocols = new int[ncols];
480  int nzerocols = 0;
481
482  int *x_to_y   = new int[ncols];
483
484#if 0
485  // follmer.mps presents a challenge, since it has some very
486  // long rows.  I started experimenting with how to deal with it,
487  // but haven't yet finished.
488  // The idea was to space out the rows to add some padding between them.
489  // Ideally, we shouldn't have to do this just here, but could try to
490  // do it a little everywhere.
491
492  // sort the row rep by reconstructing from col rep
493  copyrep(mcstrt, hrow, colels, hincol, ncols,
494          mrstrt, hcol, rowels, hinrow, nrows);
495  presolve_make_memlists(mrstrt, hinrow, rlink, nrows);
496  // NEED SOME ASSERTION ABOUT NELEMS
497
498  copyrep(mrstrt, hcol, rowels, hinrow, nrows,
499          mcstrt, hrow, colels, hincol, ncols);
500  presolve_make_memlists(mcstrt, hincol, clink, ncols);
501#endif
502
503  // in the original presolve, I don't think the two representations were
504  // kept in sync.  It may be useful not to do that here, either,
505  // but rather just keep the columns with nfill_level rows accurate
506  // and resync at the end of the function.
507
508  // DEBUGGING
509  //  int nt = 0;
510  int ngood = 0;
511  int nsubst = 0;
512#ifdef  DEBUG_PRESOLVEx
513  int maxsubst = atoi(getenv("MAXSUBST"));
514#else
515  const int maxsubst = 1000000;
516#endif
517
518  // This loop does very nearly the same thing as
519  // the first loop in implied_free_action::presolve.
520  // We have to do it again in case constraints change while we process them (???).
521  int numberLook = prob->numberColsToDo_;
522  int iLook;
523  int * look = prob->colsToDo_;
524  int fill_level = try_fill_level;
525  int * look2 = NULL;
526  // if gone from 2 to 3 look at all
527  if (fill_level<0) {
528    fill_level=-fill_level;
529    try_fill_level=fill_level;
530    look2 = new int[ncols];
531    look=look2;
532    for (iLook=0;iLook<ncols;iLook++) 
533      look[iLook]=iLook;
534    numberLook=ncols;
535 }
536 
537
538  for (iLook=0;iLook<numberLook;iLook++) {
539    int jcoly=look[iLook];
540    if (hincol[jcoly] > 1 && hincol[jcoly] <= fill_level &&
541        implied_free[jcoly] == hincol[jcoly]) {
542      CoinBigIndex kcs = mcstrt[jcoly];
543      CoinBigIndex kce = kcs + hincol[jcoly];
544
545      int bestrowy_size = 0;
546      int bestrowy_row=-1;
547      int bestrowy_k=-1;
548      double bestrowy_coeff=0.0;
549
550      for (CoinBigIndex k=kcs; k<kce; ++k) {
551        int row = hrow[k];
552        double coeffj = colels[k];
553
554        // we don't clean up zeros in the middle of the routine.
555        // if there is one, skip this candidate.
556        if (fabs(coeffj) <= ZTOLDP) {
557          bestrowy_size = 0;
558          break;
559        }
560
561        // if its row is an equality constraint...
562        if (hinrow[row] > 1 &&  // don't bother with singleton rows
563
564            fabs(rlo[row] - rup[row]) < tol) {
565          CoinBigIndex krs = mrstrt[row];
566          CoinBigIndex kre = krs + hinrow[row];
567
568          double maxup, maxdown, ilow, iup;
569
570          implied_bounds(rowels, clo, cup, hcol,
571                         krs, kre,
572                         &maxup, &maxdown,
573                         jcoly, rlo[row], rup[row], &ilow, &iup);
574
575          if (maxup < PRESOLVE_INF && maxup + tol < rlo[row]) {
576            prob->status_|= 1;
577            prob->messageHandler()->message(CLP_PRESOLVE_ROWINFEAS,
578                                             prob->messages())
579                                               <<row
580                                               <<rlo[row]
581                                               <<rup[row]
582                                               <<CoinMessageEol;
583            break;
584          } else if (-PRESOLVE_INF < maxdown && rup[row] < maxdown - tol) {
585            prob->status_|= 1;
586            prob->messageHandler()->message(CLP_PRESOLVE_ROWINFEAS,
587                                             prob->messages())
588                                               <<row
589                                               <<rlo[row]
590                                               <<rup[row]
591                                               <<CoinMessageEol;
592            break;
593          } else {
594            // the row has an implied upper or a lower bound
595
596            if (clo[jcoly] <= ilow && iup <= cup[jcoly]) {
597              // both column bounds implied by the constraint bounds
598
599              // we want coeffy to be smaller than x, BACKWARDS from in doubleton
600              if (bestrowy_size == 0 ||
601                  fabs(coeffj) > fabs(bestrowy_coeff) ||
602                  (fabs(coeffj) == fabs(bestrowy_coeff) &&
603                   hinrow[row] < bestrowy_size)) {
604                bestrowy_size = hinrow[row];
605                bestrowy_row = row;
606                bestrowy_coeff = coeffj;
607                bestrowy_k = k;
608              }
609            }
610          }
611        }
612      }
613
614      if (bestrowy_size == 0)
615        continue;
616
617      bool all_ok = true;
618      for (CoinBigIndex k=kcs; k<kce; ++k) {
619        double coeff_factor = fabs(colels[k] / bestrowy_coeff);
620        if (fabs(coeff_factor) > 1.3)
621          all_ok = false;
622      }
623
624      // check fill-in
625      if (all_ok && hincol[jcoly] == 3) {
626        // compute fill-in
627        int row1 = -1;
628        int row2=-1;
629        for (CoinBigIndex kk=kcs; kk<kce; ++kk) 
630          if (kk != bestrowy_k) {
631            if (row1 == -1)
632              row1 = hrow[kk];
633            else
634              row2 = hrow[kk];
635          }
636
637
638        CoinBigIndex krs = mrstrt[bestrowy_row];
639        CoinBigIndex kre = krs + hinrow[bestrowy_row];
640        CoinBigIndex krs1 = mrstrt[row1];
641        CoinBigIndex kre1 = krs + hinrow[row1];
642        CoinBigIndex krs2 = mrstrt[row2];
643        CoinBigIndex kre2 = krs + hinrow[row2];
644
645        CoinSort_2(hcol+krs,hcol+krs+hinrow[bestrowy_row],rowels+krs);
646        CoinSort_2(hcol+krs1,hcol+krs1+hinrow[row1],rowels+krs1);
647        CoinSort_2(hcol+krs2,hcol+krs2+hinrow[row2],rowels+krs2);
648        //ekk_sort2(hcol+krs,  rowels+krs,  hinrow[bestrowy_row]);
649        //ekk_sort2(hcol+krs1, rowels+krs1, hinrow[row1]);
650        //ekk_sort2(hcol+krs2, rowels+krs2, hinrow[row2]);
651
652        int nfill = -hinrow[bestrowy_row];
653        CoinBigIndex kcol1 = krs1;
654        for (CoinBigIndex kk=krs; kk<kre; ++kk) {
655          int jcol = hcol[kk];
656
657          while (kcol1 < kre1 && hcol[kcol1] < jcol)
658            kcol1++;
659          if (! (kcol1 < kre1 && hcol[kcol1] == jcol))
660            nfill++;
661        }
662        CoinBigIndex kcol2 = krs2;
663        for (CoinBigIndex kk=krs; kk<kre; ++kk) {
664          int jcol = hcol[kk];
665
666          while (kcol2 < kre2 && hcol[kcol2] < jcol)
667            kcol2++;
668          if (! (kcol2 < kre2 && hcol[kcol2] == jcol))
669            nfill++;
670        }
671#if     DEBUG_PRESOLVE
672        printf("FILL:  %d\n", nfill);
673#endif
674
675#if 0
676        static int maxfill = atoi(getenv("MAXFILL"));
677
678        if (nfill > maxfill)
679          all_ok = false;
680#endif
681
682        // not too much
683        if (nfill <= 0)
684          ngood++;
685
686#if 0
687        static int nts = 0;
688        if (++nts > atoi(getenv("NTS")))
689          all_ok = false;
690        else
691          nt++;
692#endif
693      }
694
695      // probably never happens
696      if (all_ok && nzerocols + hinrow[bestrowy_row] >= ncols)
697        all_ok = false;
698
699      if (nsubst >= maxsubst) {
700        all_ok = false;
701      } 
702
703      if (all_ok) {
704        nsubst++;
705#if 0
706        // debug
707        if (numberLook<ncols&&iLook==numberLook-1) {
708          printf("found last one?? %d\n", jcoly);
709        }
710#endif
711
712        CoinBigIndex kcs = mcstrt[jcoly];
713        int rowy = bestrowy_row;
714        double coeffy = bestrowy_coeff;
715
716        PRESOLVEASSERT(fabs(colels[kcs]) > ZTOLDP);
717        PRESOLVEASSERT(fabs(colels[kcs+1]) > ZTOLDP);
718
719        PRESOLVEASSERT(hinrow[rowy] > 1);
720
721        const bool nonzero_cost = (fabs(dcost[jcoly]) > tol);
722
723        double *costsx = nonzero_cost ? new double[hinrow[rowy]] : 0;
724
725        int ntotels = 0;
726        for (CoinBigIndex k=kcs; k<kce; ++k) {
727          int irow = hrow[k];
728          ntotels += hinrow[irow];
729        }
730
731        {
732          action *ap = &actions[nactions++];
733          int nincol = hincol[jcoly];
734
735          ap->col = jcoly;
736          ap->rowy = rowy;
737
738          ap->nincol = nincol;
739          ap->rows = new int[nincol];
740          ap->rlos = new double[nincol];
741          ap->rups = new double[nincol];
742
743          // coefficients in deleted col
744          ap->coeffxs = new double[nincol];
745
746          ap->ninrowxs = new int[nincol];
747          ap->rowcolsxs = new int[ntotels];
748          ap->rowelsxs = new double[ntotels];
749
750          ap->costsx = costsx;
751
752          // copy all the rows for restoring later - wasteful
753          {
754            int nel = 0;
755            for (CoinBigIndex k=kcs; k<kce; ++k) {
756              int irow = hrow[k];
757              CoinBigIndex krs = mrstrt[irow];
758              //              CoinBigIndex kre = krs + hinrow[irow];
759
760              prob->addRow(irow);
761              ap->rows[k-kcs] = irow;
762              ap->ninrowxs[k-kcs] = hinrow[irow];
763              ap->rlos[k-kcs] = rlo[irow];
764              ap->rups[k-kcs] = rup[irow];
765
766              ap->coeffxs[k-kcs] = colels[k];
767
768              bcopy(&hcol[krs], &ap->rowcolsxs[nel], hinrow[irow]*sizeof(int));
769              bcopy(&rowels[krs], &ap->rowelsxs[nel], hinrow[irow]*sizeof(double));
770              nel += hinrow[irow];
771            }
772          }
773        }
774
775        // rowy is supposed to be an equality row
776        PRESOLVEASSERT(fabs(rup[rowy] - rlo[rowy]) < ZTOLDP);
777
778        // now adjust for the implied free row - COPIED
779        if (nonzero_cost) {
780#ifdef  DEBUG_PRESOLVE
781          printf("NONZERO SUBST COST:  %d %g\n", jcoly, dcost[jcoly]);
782#endif
783          double *cost = dcost;
784          double *save_costs = costsx;
785          double coeffj = coeffy;
786          CoinBigIndex krs = mrstrt[rowy];
787          CoinBigIndex kre = krs + hinrow[rowy];
788
789          double rhs = rlo[rowy];
790          double costj = cost[jcoly];
791
792          for (CoinBigIndex k=krs; k<kre; k++) {
793            int jcol = hcol[k];
794            prob->addCol(jcol);
795            save_costs[k-krs] = cost[jcol];
796
797            if (jcol != jcoly) {
798              double coeff = rowels[k];
799
800              /*
801               * Similar to eliminating doubleton:
802               *   cost1 x = cost1 (c - b y) / a = (c cost1)/a - (b cost1)/a
803               *   cost[icoly] += cost[icolx] * (-coeff2 / coeff1);
804               */
805              cost[jcol] += costj * (-coeff / coeffj);
806            }
807          }
808
809          // I'm not sure about this
810          prob->change_bias(costj * rhs / coeffj);
811
812          // ??
813          cost[jcoly] = 0.0;
814        }
815
816#if     DEBUG_PRESOLVE
817            if (hincol[jcoly] == 3) {
818              CoinBigIndex krs = mrstrt[rowy];
819              CoinBigIndex kre = krs + hinrow[rowy];
820              printf("HROW0 (%d):  ", rowy);
821              for (CoinBigIndex k=krs; k<kre; ++k) {
822                int jcol = hcol[k];
823                double coeff = rowels[k];
824                printf("%d:%g (%d) ", jcol, coeff, hincol[jcol]);
825              }
826              printf("\n");
827            }
828#endif
829
830            if (hincol[jcoly] != 2) {
831              CoinBigIndex krs = mrstrt[rowy];
832              //              CoinBigIndex kre = krs + hinrow[rowy];
833              CoinSort_2(hcol+krs,hcol+krs+hinrow[rowy],rowels+krs);
834              //ekk_sort2(hcol+krs,  rowels+krs,  hinrow[rowy]);
835            }
836
837            // substitute away jcoly in the other rows
838            // Use ap as mcstrt etc may move if compacted
839            kce = hincol[jcoly];
840            CoinBigIndex k;
841            action *ap = &actions[nactions-1];
842            for (k=0; k<kce; ++k) {
843              int rowx = ap->rows[k];
844              //assert(rowx==hrow[k+kcs]);
845              //assert(ap->coeffxs[k]==colels[k+kcs]);
846              if (rowx != rowy) {
847                double coeffx = ap->coeffxs[k];
848                double coeff_factor = -coeffx / coeffy; // backwards from doubleton
849
850#if     DEBUG_PRESOLVE
851                {
852                  CoinBigIndex krs = mrstrt[rowx];
853                  CoinBigIndex kre = krs + hinrow[rowx];
854                  printf("HROW (%d %d %d):  ", rowx, hinrow[rowx], jcoly);
855                  for (CoinBigIndex k=krs; k<kre; ++k) {
856                    int jcol = hcol[k];
857                    double coeff = rowels[k];
858                    printf("%d ", jcol);
859                  }
860                  printf("\n");
861#if 0
862                  for (CoinBigIndex k=krs; k<kre; ++k) {
863                    int jcol = hcol[k];
864                    prob->addCol(jcol);
865                    double coeff = rowels[k];
866                    printf("%g ", coeff);
867                  }
868                  printf("\n");
869#endif
870                }
871#endif
872                {
873                  CoinBigIndex krsx = mrstrt[rowx];
874                  CoinBigIndex krex = krsx + hinrow[rowx];
875                  int i;
876                  for (i=krsx;i<krex;i++) 
877                    prob->addCol(hcol[i]);
878                  if (hincol[jcoly] != 2) 
879                    CoinSort_2(hcol+krsx,hcol+krsx+hinrow[rowx],rowels+krsx);
880                  //ekk_sort2(hcol+krsx, rowels+krsx, hinrow[rowx]);
881                }
882               
883                // add (coeff_factor * <rowy>) to rowx
884                // does not affect rowy
885                // may introduce (or cancel) elements in rowx
886                add_row(mrstrt,
887                        rlo, acts, rup,
888                        rowels, hcol,
889                        hinrow,
890                        rlink, nrows,
891                        coeff_factor,
892                        rowx, rowy,
893                        x_to_y);
894               
895                // update col rep of rowx from row rep:
896                // for every col in rowy, copy the elem for that col in rowx
897                // from the row rep to the col rep
898                {
899                  CoinBigIndex krs = mrstrt[rowy];
900                  //              CoinBigIndex kre = krs + hinrow[rowy];
901                  int niny = hinrow[rowy];
902                 
903                  CoinBigIndex krsx = mrstrt[rowx];
904                  //              CoinBigIndex krex = krsx + hinrow[rowx];
905                  for (CoinBigIndex ki=0; ki<niny; ++ki) {
906                    CoinBigIndex k = krs + ki;
907                    int jcol = hcol[k];
908                    prob->addCol(jcol);
909                    CoinBigIndex kcs = mcstrt[jcol];
910                    CoinBigIndex kce = kcs + hincol[jcol];
911                   
912                    //double coeff = rowels[presolve_find_row(jcol, krsx, krex, hcol)];
913                    if (hcol[krsx + x_to_y[ki]] != jcol)
914                      abort();
915                    double coeff = rowels[krsx + x_to_y[ki]];
916                   
917                    // see if rowx appeared in jcol in the col rep
918                    CoinBigIndex k2 = presolve_find_row1(rowx, kcs, kce, hrow);
919                   
920                    //PRESOLVEASSERT(fabs(coeff) > ZTOLDP);
921                   
922                    if (k2 < kce) {
923                      // yes - just update the entry
924                      colels[k2] = coeff;
925                    } else {
926                      // no - make room, then append
927                      expand_row(mcstrt, colels, hrow, hincol, clink, ncols, jcol);
928                      kcs = mcstrt[jcol];
929                      kce = kcs + hincol[jcol];
930                     
931                      hrow[kce] = rowx;
932                      colels[kce] = coeff;
933                      hincol[jcol]++;
934                    }
935                  }
936                }
937                // now colels[k] == 0.0
938
939#if 1
940                // now remove jcoly from rowx in the row rep
941                // better if this were first
942                presolve_delete_from_row(rowx, jcoly, mrstrt, hinrow, hcol, rowels);
943#endif
944#if     DEBUG_PRESOLVE
945                {
946                  CoinBigIndex krs = mrstrt[rowx];
947                  CoinBigIndex kre = krs + hinrow[rowx];
948                  printf("HROW (%d %d %d):  ", rowx, hinrow[rowx], jcoly);
949                  for (CoinBigIndex k=krs; k<kre; ++k) {
950                    int jcol = hcol[k];
951                    double coeff = rowels[k];
952                    printf("%d ", jcol);
953                  }
954                  printf("\n");
955#if 0
956                  for (CoinBigIndex k=krs; k<kre; ++k) {
957                    int jcol = hcol[k];
958                    double coeff = rowels[k];
959                    printf("%g ", coeff);
960                  }
961                  printf("\n");
962#endif
963                }
964#endif
965               
966                // don't have to update col rep, since entire col deleted later
967              }
968            }
969
970#if     DEBUG_PRESOLVE
971            printf("\n");
972#endif
973
974            // the addition of rows may have created zero coefficients
975            bcopy(&hcol[mrstrt[rowy]], &zerocols[nzerocols], hinrow[rowy]*sizeof(int));
976            nzerocols += hinrow[rowy];
977           
978            // delete rowy in col rep
979            {
980              CoinBigIndex krs = mrstrt[rowy];
981              CoinBigIndex kre = krs + hinrow[rowy];
982              for (CoinBigIndex k=krs; k<kre; ++k) {
983                int jcol = hcol[k];
984               
985                // delete rowy from the jcol
986                presolve_delete_from_row(jcol, rowy, mcstrt, hincol, hrow, colels);
987              }
988            }
989            // delete rowy in row rep
990            hinrow[rowy] = 0;
991           
992            // This last is entirely dual to doubleton, but for the cost adjustment
993           
994            // eliminate col entirely from the col rep
995            PRESOLVE_REMOVE_LINK(clink, jcoly);
996            hincol[jcoly] = 0;
997           
998            // eliminate rowy entirely from the row rep
999            PRESOLVE_REMOVE_LINK(rlink, rowy);
1000            //cost[irowy] = 0.0;
1001           
1002            rlo[rowy] = 0.0;
1003            rup[rowy] = 0.0;
1004           
1005#if     0 && DEBUG_PRESOLVE
1006            printf("ROWY COLS:  ");
1007            for (CoinBigIndex k=0; k<save_ninrowy; ++k)
1008              if (rowycols[k] != col) {
1009                printf("%d ", rowycols[k]);
1010                (void)presolve_find_row(rowycols[k], mrstrt[rowx], mrstrt[rowx]+hinrow[rowx],
1011                                        hcol);
1012              }
1013            printf("\n");
1014#endif
1015#if 0
1016        presolve_links_ok(clink, mcstrt, hincol, ncols);
1017        presolve_links_ok(rlink, mrstrt, hinrow, nrows);
1018        prob->consistent();
1019#endif
1020      }
1021    }
1022  }
1023
1024  // general idea - only do doubletons until there are almost none left
1025  if (nactions < 30&&fill_level==2)
1026    try_fill_level = -3;
1027
1028  if (nactions) {
1029#if     PRESOLVE_SUMMARY
1030    printf("NSUBSTS:  %d\n", nactions);
1031    printf("NT: %d  NGOOD:  %d FILL_LEVEL:  %d\n", nt, ngood, fill_level);
1032#endif
1033    next = new subst_constraint_action(nactions, copyOfArray(actions,nactions), next);
1034
1035    next = drop_zero_coefficients_action::presolve(prob, zerocols, nzerocols, next);
1036  }
1037  delete [] look2;
1038  delete [] actions;
1039
1040  delete[]x_to_y;
1041  delete[]zerocols;
1042
1043  return (next);
1044}
1045
1046
1047void subst_constraint_action::postsolve(PostsolveMatrix *prob) const
1048{
1049  const action *const actions = actions_;
1050  const int nactions    = nactions_;
1051
1052  double *colels        = prob->colels_;
1053  int *hrow             = prob->hrow_;
1054  CoinBigIndex *mcstrt          = prob->mcstrt_;
1055  int *hincol           = prob->hincol_;
1056  int *link             = prob->link_;
1057  //  int ncols         = prob->ncols_;
1058
1059  double *clo   = prob->clo_;
1060  double *cup   = prob->cup_;
1061
1062  double *rlo   = prob->rlo_;
1063  double *rup   = prob->rup_;
1064
1065  double *dcost = prob->cost_;
1066
1067  double *sol   = prob->sol_;
1068  double *rcosts        = prob->rcosts_;
1069
1070  double *acts  = prob->acts_;
1071  double *rowduals = prob->rowduals_;
1072
1073  char *cdone   = prob->cdone_;
1074  char *rdone   = prob->rdone_;
1075  CoinBigIndex free_list = prob->free_list_;
1076
1077  const double ztolzb   = prob->ztolzb_;
1078  //  const double ztoldj       = prob->ztoldj_;
1079  const double maxmin = prob->maxmin_;
1080
1081  for (const action *f = &actions[nactions-1]; actions<=f; f--) {
1082    int icol = f->col;
1083
1084    int nincoly = f->nincol;
1085    double *rlos = f->rlos;
1086    double *rups = f->rups;
1087    int *rows = f->rows;
1088
1089    double *coeffxs = f->coeffxs;
1090
1091    int jrowy = f->rowy;
1092
1093    int *ninrowxs = f->ninrowxs;
1094    const int *rowcolsxs = f->rowcolsxs;
1095    const double *rowelsxs = f->rowelsxs;
1096   
1097    /* the row was in the reduced problem */
1098    for (int i=0; i<nincoly; ++i) {
1099      if (rows[i] != jrowy)
1100        PRESOLVEASSERT(rdone[rows[i]]);
1101    }
1102    PRESOLVEASSERT(cdone[icol]==DROP_COL);
1103    PRESOLVEASSERT(rdone[jrowy]==DROP_ROW);
1104
1105    // DEBUG CHECK
1106#if     0 && DEBUG_PRESOLVE
1107    {
1108      double actx = 0.0;
1109      for (int j=0; j<ncols; ++j)
1110        if (hincol[j] > 0 && cdone[j]) {
1111          CoinBigIndex krow = presolve_find_row1(jrowx, mcstrt[j], mcstrt[j] + hincol[j], hrow);
1112          if (krow < mcstrt[j] + hincol[j])
1113            actx += colels[krow] * sol[j];
1114      }
1115      if (! (fabs(acts[jrowx] - actx) < 100*ztolzb))
1116        printf("BAD ACTSX:  acts[%d]==%g != %g\n",
1117               jrowx, acts[jrowx], actx);
1118      if (! (rlo[jrowx] - 100*ztolzb <= actx && actx <= rup[jrowx] + 100*ztolzb))
1119        printf("ACTSX NOT IN RANGE:  %d %g %g %g\n",
1120               jrowx, rlo[jrowx], actx, rup[jrowx]);
1121    }
1122#endif
1123
1124    int ninrowy=-1;
1125    const int *rowcolsy=NULL;
1126    const double *rowelsy=NULL;
1127    double coeffy=0.0;
1128
1129    double rloy=1.0e50;
1130    {
1131      int nel = 0;
1132      for (int i=0; i<nincoly; ++i) {
1133        int row = rows[i];
1134        rlo[row] = rlos[i];
1135        rup[row] = rups[i];
1136        if (row == jrowy) {
1137          ninrowy = ninrowxs[i];
1138          rowcolsy = &rowcolsxs[nel];
1139          rowelsy  = &rowelsxs[nel];
1140
1141          coeffy = coeffxs[i];
1142          rloy = rlo[row];
1143
1144        }
1145        nel += ninrowxs[i];
1146      }
1147    }
1148    double rhsy = rloy;
1149
1150    // restore costs
1151    {
1152      const double *costs = f->costsx;
1153      if (costs)
1154        for (int i = 0; i<ninrowy; ++i) {
1155          dcost[rowcolsy[i]] = costs[i];
1156        }
1157    }
1158
1159    // solve for the equality to find the solution for the eliminated col
1160    // this is why we want coeffx < coeffy (55)
1161    {
1162      double sol0 = rloy;
1163      sol[icol] = 0.0;  // to avoid condition in loop
1164      for (int k = 0; k<ninrowy; ++k) {
1165        int jcolx = rowcolsy[k];
1166        double coeffx = rowelsy[k];
1167        sol0 -= coeffx * sol[jcolx];
1168      }
1169      sol[icol] = sol0 / coeffy;
1170
1171      if (! (sol[icol] > clo[icol] - ztolzb &&
1172             cup[icol] + ztolzb > sol[icol]))
1173        printf("NEW SOL OUT-OF-TOL:  %g %g %g\n", clo[icol], sol[icol], cup[icol]);
1174    }
1175
1176    // since this row is fixed
1177    acts[jrowy] = rloy;
1178
1179    // acts[irow] always ok, since slack is fixed
1180    prob->setRowStatus(jrowy,PrePostsolveMatrix::atLowerBound);
1181
1182    // remove old rowx from col rep
1183    // we don't explicitly store what the current rowx is;
1184    // however, after the presolve, rowx contains a col for every
1185    // col in either the original rowx or the original rowy.
1186    // If there were cancellations, those were handled in subsequent
1187    // presolves.
1188    {
1189      // erase those cols in the other rows that occur in rowy
1190      // (with the exception of icol, which was deleted);
1191      // the other rows *must* contain these cols
1192      for (int k = 0; k<ninrowy; ++k) {
1193        int col = rowcolsy[k];
1194
1195        // remove jrowx from col in the col rep
1196        // icol itself was deleted, so won't be there
1197        if (col != icol)
1198          for (int i = 0; i<nincoly; ++i) {
1199            if (rows[i] != jrowy)
1200              presolve_delete_from_row2(col, rows[i], mcstrt, hincol, hrow, colels, link, &free_list);
1201          }
1202      }
1203
1204      // initialize this for loops below
1205      hincol[icol] = 0;
1206
1207      // now restore the original rows (other than rowy).
1208      // those cols that were also in rowy were just removed;
1209      // otherwise, they *must* already be there.
1210      // This loop and the next automatically create the rep for the new col.
1211      {
1212        const int *rowcolsx = rowcolsxs;
1213        const double *rowelsx = rowelsxs;
1214
1215        for (int i = 0; i<nincoly; ++i) {
1216          int ninrowx = ninrowxs[i];
1217          int jrowx = rows[i];
1218
1219          if (jrowx != jrowy)
1220            for (int k = 0; k<ninrowx; ++k) {
1221              int col = rowcolsx[k];
1222              CoinBigIndex kcolx = presolve_find_row3(jrowx, mcstrt[col], hincol[col], hrow, link);
1223
1224              if (kcolx != -1) {
1225                PRESOLVEASSERT(presolve_find_row1(col, 0, ninrowy, rowcolsy) == ninrowy);
1226                // overwrite the existing entry
1227                colels[kcolx] = rowelsx[k];
1228              } else {
1229                PRESOLVEASSERT(presolve_find_row1(col, 0, ninrowy, rowcolsy) < ninrowy);
1230
1231                {
1232                  CoinBigIndex kk = free_list;
1233                  free_list = link[free_list];
1234                  check_free_list(free_list);
1235
1236                  link[kk] = mcstrt[col];
1237                  mcstrt[col] = kk;
1238                  colels[kk] = rowelsx[k];
1239                  hrow[kk] = jrowx;
1240                }
1241                ++hincol[col];
1242              }
1243            }
1244          rowcolsx += ninrowx;
1245          rowelsx += ninrowx;
1246        }
1247      }
1248
1249      // finally, add original rowy elements
1250      for (int k = 0; k<ninrowy; ++k) {
1251        int col = rowcolsy[k];
1252
1253        {
1254          prepend_elem(col, rowelsy[k], jrowy, mcstrt, colels, hrow, link, &free_list);
1255          ++hincol[col];
1256        }
1257      }
1258    }
1259
1260    // my guess is that the CLAIM in doubleton generalizes to
1261    // equations with more than one x-style variable.
1262    // Since I can't see how to distinguish among them,
1263    // I assume that any of them will do.
1264
1265    {
1266       //      CoinBigIndex k;
1267      double dj = maxmin*dcost[icol];
1268      double bounds_factor = rhsy/coeffy;
1269      for (int i=0; i<nincoly; ++i)
1270        if (rows[i] != jrowy) {
1271          int row = rows[i];
1272          double coeff = coeffxs[i];
1273
1274          // PROBABLY DOESN'T MAKE SENSE
1275          acts[row] += coeff * bounds_factor;
1276
1277          dj -= rowduals[row] * coeff;
1278        }
1279
1280      // DEBUG CHECK
1281      double acty = 0.0;
1282      for (int k = 0; k<ninrowy; ++k) {
1283        int col = rowcolsy[k];
1284        acty += rowelsy[k] * sol[col];
1285      }
1286      PRESOLVEASSERT(fabs(acty - acts[jrowy]) < 100*ZTOLDP);
1287
1288      // RECOMPUTING
1289      {
1290        const int *rowcolsx = rowcolsxs;
1291        const double *rowelsx = rowelsxs;
1292
1293        for (int i=0; i<nincoly; ++i) {
1294          int ninrowx = ninrowxs[i];
1295
1296          if (rows[i] != jrowy) {
1297            int jrowx = rows[i];
1298
1299            double actx = 0.0;
1300            for (int k = 0; k<ninrowx; ++k) {
1301              int col = rowcolsx[k];
1302              actx += rowelsx[k] * sol[col];
1303            }
1304#if     DEBUG_PRESOLVE
1305            PRESOLVEASSERT(rlo[jrowx] - ztolzb <= actx && actx <= rup[jrowx] + ztolzb);
1306#endif
1307            acts[jrowx] = actx;
1308          }
1309          rowcolsx += ninrowx;
1310          rowelsx += ninrowx;
1311        }
1312      }
1313
1314      // this is the coefficient we need to force col y's reduced cost to 0.0;
1315      // for example, this is obviously true if y is a singleton column
1316      rowduals[jrowy] = dj / coeffy;
1317      rcosts[icol] = 0.0;
1318
1319      // furthermore, this should leave rcosts[colx] for all colx
1320      // in jrowx unchanged (????).
1321    }
1322
1323    // Unlike doubleton, there should never be a problem with keeping
1324    // the reduced costs the way they were, because the other
1325    // variable's bounds are never changed, since col was implied free.
1326    //rowstat[jrowy] = 0;
1327    prob->setColumnStatus(icol,PrePostsolveMatrix::basic);
1328
1329    cdone[icol] = SUBST_ROW;
1330    rdone[jrowy] = SUBST_ROW;
1331  }
1332
1333  prob->free_list_ = free_list;
1334}
1335
1336
1337
1338subst_constraint_action::~subst_constraint_action()
1339{
1340  const action *actions = actions_;
1341
1342  for (int i=0; i<nactions_; ++i) {
1343    delete[]actions[i].rows;
1344    delete[]actions[i].rlos;
1345    delete[]actions[i].rups;
1346    delete[]actions[i].coeffxs;
1347    delete[]actions[i].ninrowxs;
1348    delete[]actions[i].rowcolsxs;
1349    delete[]actions[i].rowelsxs;
1350    delete[]actions[i].costsx;
1351  }
1352
1353  delete[]actions;
1354
1355}
Note: See TracBrowser for help on using the repository browser.