source: tags/clp-0-94-0/PresolveDupcol.cpp @ 1814

Last change on this file since 1814 was 63, checked in by jpfasano, 17 years ago

-modified to use CoinPragma?.h
-modified to compile w/MS Visual C++ and gcc (on cygwin) without errors or warnings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.1 KB
Line 
1#include <stdio.h>
2#include <math.h>
3
4#include "PresolveMatrix.hpp"
5#include "PresolveFixed.hpp"
6#include "PresolveDupcol.hpp"
7#include "CoinSort.hpp"
8
9#define DSEED2 2147483647.0
10
11const char *dupcol_action::name() const
12{
13  return ("dupcol_action");
14}
15
16const char *duprow_action::name() const
17{
18  return ("duprow_action");
19}
20
21void init_random_vec(double *work, int n)
22{
23  double deseed = 12345678.0;
24
25  for (int i = 0; i < n; ++i) {
26    deseed *= 16807.;
27    int jseed = (int) (deseed /    DSEED2);
28    deseed -= (double) jseed * DSEED2;
29    double random = deseed /  DSEED2;
30
31    work[i]=random;
32  }
33}
34
35int compute_sums(const int *len, const CoinBigIndex *starts,
36                 /*const*/ int *index, /*const*/ double *elems, // index/elems are sorted
37                 const double *work,
38                 double *sums, int *sorted, int n)
39{
40  int nlook=0;
41  for (int i = 0; i < n; ++i)
42    if (len[i] > 0 /*1?*/) {
43      CoinBigIndex kcs = starts[i];
44      CoinBigIndex kce = kcs + len[i];
45
46      double value=0.0;
47
48      // sort all columns for easy comparison in next loop
49      CoinSort_2(index+kcs,index+kcs+len[i],elems+kcs);
50      //ekk_sort2(index+kcs, elems+kcs, len[i]);
51
52      for (CoinBigIndex k=kcs;k<kce;k++) {
53        int irow=index[k];
54        value += work[irow]*elems[k];
55      }
56      sums[nlook]=value;
57      sorted[nlook]=i;
58      ++nlook;
59    }
60  return (nlook);
61}
62
63dupcol_action::dupcol_action(int nactions,
64                const action *actions,
65                const PresolveAction *next) :
66    PresolveAction(next),
67    nactions_(nactions), actions_(actions)
68{
69}
70
71
72// This is just ekkredc5, adapted into the new framework.
73// the datasets scorpion.mps and allgrade.mps have duplicate columns.
74const PresolveAction *dupcol_action::presolve(PresolveMatrix *prob,
75                                               const PresolveAction *next)
76{
77  double *colels        = prob->colels_;
78  int *hrow             = prob->hrow_;
79  CoinBigIndex *mcstrt          = prob->mcstrt_;
80  int *hincol           = prob->hincol_;
81  int ncols             = prob->ncols_;
82
83  double *clo   = prob->clo_;
84  double *cup   = prob->cup_;
85  double * sol = prob->sol_;
86
87  double *rowels        = prob->rowels_;
88  int *hcol     = prob->hcol_;
89  const CoinBigIndex *mrstrt    = prob->mrstrt_;
90  int *hinrow           = prob->hinrow_;
91  int nrows             = prob->nrows_;
92
93  //  double *rlo       = prob->rlo_;
94  //  double *rup       = prob->rup_;
95
96  double *dcost = prob->cost_;
97
98  const char *integerType = prob->integerType_;
99
100  double maxmin = prob->maxmin_;
101
102  action *actions       = new action [ncols];
103  int nactions = 0;
104
105  int *fixed_down       = new int[ncols];
106  int nfixed_down       = 0;
107  int *fixed_up         = new int[ncols];
108  int nfixed_up         = 0;
109
110  double * workcol = new double[ncols];
111  double * workrow = new double[nrows];
112  int * sort = new int[ncols];
113
114  // initialize workrow to have "random" values
115  init_random_vec(workrow, nrows);
116
117  // If we sum all the coefficients of a column,
118  // then duplicate columns must have the same sum.
119  // However, other columns may also.
120  // To weed most of them out, we multiply the coefficients
121  // by the random value associated with the row.
122  int nlook = compute_sums(hincol, mcstrt, hrow, colels, workrow, workcol, sort, ncols);
123#if 0
124  int nlook=0;
125  for (int i = 0; i < ncols; ++i)
126    if (hincol[i] > 0 /*1?*/) {
127      CoinBigIndex kcs = mcstrt[i];
128      CoinBigIndex kce = kcs + hincol[i];
129
130      double value=0.0;
131
132      // sort all columns for easy comparison in next loop
133      CoinSort_2(hrow+kcs,hrow+kcs+hincol[i],colels+kcs);
134      //ekk_sort2(hrow+kcs, colels+kcs, hincol[i]);
135
136      for (CoinBigIndex k=kcs;k<kce;k++) {
137        int irow=hrow[k];
138        value += workrow[irow]*colels[k];
139      }
140      workcol[nlook]=value;
141      sort[nlook]=i;
142      ++nlook;
143    }
144#endif
145
146#if 1
147  // not tested yet
148  if (maxmin < 0.0)
149    return (next);
150#endif
151
152  CoinSort_2(workcol,workcol+nlook,sort);
153  //ekk_sortonDouble(workcol,sort,nlook);
154
155#if 0
156  // It may be the case that several columns are duplicate.
157  // If not all have the same cost, then we have to make sure
158  // that we set the most expensive one to its minimum
159  // now sort in each class by cost
160  {
161    double dval = workcol[0];
162    int first = 0;
163    for (int jj = 1; jj < nlook; jj++) {
164      while (workcol[jj]==dval)
165        jj++;
166
167      if (first + 1 < jj) {
168        double buf[jj - first];
169        for (int i=first; i<jj; ++i)
170          buf[i-first] = dcost[sort[i]]*maxmin;
171
172        CoinSort_2(buf,buf+jj-first,sort+first);
173        //ekk_sortonDouble(buf,&sort[first],jj-first);
174      }
175    }
176  }
177#endif
178
179  // it appears to be the case that this loop is finished,
180  // there may still be duplicate cols left.
181  // I haven't done anything about that yet.
182  for (int jj = 1; jj < nlook; jj++) {
183    if (workcol[jj]==workcol[jj-1]) {
184      int ithis=sort[jj];
185      int ilast=sort[jj-1];
186      CoinBigIndex kcs = mcstrt[ithis];
187      CoinBigIndex kce = kcs + hincol[ithis];
188
189      if (hincol[ithis] == hincol[ilast]) {
190        int ishift = mcstrt[ilast] - kcs;
191        CoinBigIndex k;
192        for (k=kcs;k<kce;k++) {
193          if (hrow[k] != hrow[k+ishift] ||
194              colels[k] != colels[k+ishift]) {
195            break;
196          }
197        }
198        if (k == kce) {
199          // these really are duplicate columns
200
201          /* now check bounds and costs to see what is what */
202          double clo1=clo[ilast];
203          double cup1=cup[ilast];
204          double clo2=clo[ithis];
205          double cup2=cup[ithis];
206          double dcost1=dcost[ilast]*maxmin;
207          double dcost2=dcost[ithis]*maxmin;
208          double newSolution = sol[ilast]+sol[ithis];
209          //int itype=27;
210          if (clo1==cup1||clo2==cup2)
211            abort();
212
213          if (/*ddjs[ilast]||ddjs[ithis]*/
214              integerType[ilast] || integerType[ithis]) {
215#ifdef PRINT_DEBUG
216            printf("at least one of %d or %d integer\n",ilast-nrowsmx,
217                   ithis-nrowsmx);
218#endif
219            continue;
220          } else if (dcost1==dcost2) {
221            //
222            // SAME COSTS
223            //
224            double l_j = clo[ithis];
225            double u_j = cup[ithis];
226            double l_k = clo[ilast];
227            double u_k = cup[ilast];
228
229            if (! (l_j + u_k <= l_k + u_j)) {
230              swap(ilast, ithis);
231              swap(clo1, clo2);
232              swap(cup1, cup2);
233              //swap(dcost1, dcost2);
234            }
235
236            //PRESOLVE_STMT(printf("DUPCOL (%d,%d)\n", ithis, ilast));
237
238            /* identical cost so can add ranges */
239            clo1 += clo2;
240            cup1 += cup2;
241            if (clo1<-1.0e20) {
242              clo1=-1.0e31;
243            }
244            if (cup1>1.0e20) {
245              cup1=1.0e31;
246            }
247            /*dfix=0.0;*/
248            //itype=26;
249
250            {
251              action *s = &actions[nactions];     
252              nactions++;
253
254              s->thislo = clo[ithis];
255              s->thisup = cup[ithis];
256              s->lastlo = clo[ilast];
257              s->lastup = cup[ilast];
258              s->ithis  = ithis;
259              s->ilast  = ilast;
260
261              s->nincol = hincol[ithis];
262              s->colels = copyOfArray(&colels[mcstrt[ithis]], hincol[ithis]);
263              s->colrows= copyOfArray(&hrow[mcstrt[ithis]], hincol[ithis]);
264            }
265
266            // adjust ilast
267            clo[ilast]=clo1;
268            cup[ilast]=cup1;
269            sol[ilast] = newSolution;
270            if (prob->getColumnStatus(ilast)==PrePostsolveMatrix::basic||
271                prob->getColumnStatus(ithis)==PrePostsolveMatrix::basic)
272              prob->setColumnStatus(ilast,PrePostsolveMatrix::basic);
273
274            // delete ithis
275            dcost[ithis] = 0.0;
276            sol[ithis]=clo2;
277            {
278              CoinBigIndex kcs = mcstrt[ithis];
279              CoinBigIndex kce = kcs + hincol[ithis];
280              for (CoinBigIndex k=kcs; k<kce; ++k)
281                // delete ithis from its rows
282                presolve_delete_from_row(hrow[k], ithis, mrstrt, hinrow, hcol, rowels);
283            }
284            hincol[ithis] = 0;
285
286            /* make sure fixed one out of way */
287            sort[jj] = ilast;
288            //if (ithis==sort[jj]) {
289            //sort[jj]=sort[jj-1];
290            //}
291          } else {
292            //
293            // (dcost1!=dcost2) - DIFFERENT COSTS
294            //
295#define PRINT_DEBUG
296            /* look to see whether we can drop one ? */
297            if (clo1<-1.0e20 && clo2<-1.0e20) {
298              // both unbounded below
299              /* can't cope for now */
300#ifdef PRINT_DEBUG
301              printf("** Odd columns %d and %d\n", ilast,ithis);
302#endif
303              continue;
304            } else if (clo1<-1.0e20) {
305              printf("ILAST:  %d %d\n", ilast, ithis);
306              swap(ilast, ithis);
307              printf("ILAST1:  %d %d\n", ilast, ithis);
308              swap(clo1, clo2);
309              swap(cup1, cup2);
310              swap(dcost1, dcost2);
311            }
312            // first one (ilast) bounded below - PRESOLVEASSERT(! (clo1<-1.0e20) );
313
314            if (cup1>1.0e20) {
315              /* ilast can go to plus infinity */
316              if (clo2<-1.0e20) {
317                if (dcost1<dcost2) {
318#ifdef PRINT_DEBUG
319                  printf("** Problem seems unbounded %d and %d\n", ilast,ithis);
320#endif
321                  break;
322                } else {
323                  continue;
324                }
325              } else if (cup2>1.0e20) {
326                //PRESOLVE_STMT(printf("DUPCOL1 (%d,%d) %g\n", ithis, ilast, workcol[jj]));
327                // both have an lb, both have no ub
328                // the more expensive one would end up at its lb
329                if (dcost1>dcost2) {
330                  swap(ilast, ithis);
331                  swap(clo1, clo2);
332                  swap(cup1, cup2);
333                  swap(dcost1, dcost2);
334                }
335                sol[ilast] = newSolution;
336                if (prob->getColumnStatus(ilast)==PrePostsolveMatrix::basic||
337                    prob->getColumnStatus(ithis)==PrePostsolveMatrix::basic)
338                  prob->setColumnStatus(ilast,PrePostsolveMatrix::basic);
339               
340                sol[ithis]=clo2;
341                fixed_down[nfixed_down++] = ithis ;
342                sort[jj]                  = ilast;
343              } else {
344                /* ithis ranged - last not */
345                if (dcost2>dcost1) {
346                  //PRESOLVE_STMT(printf("DUPCOL2 (%d,%d)\n", ithis, ilast));
347                  /* set ithis to lower bound */
348                  fixed_down[nfixed_down++] = ithis;
349                  sort[jj] = ilast;
350                  sol[ilast] = newSolution;
351                  if (prob->getColumnStatus(ilast)==PrePostsolveMatrix::basic||
352                      prob->getColumnStatus(ithis)==PrePostsolveMatrix::basic)
353                    prob->setColumnStatus(ilast,PrePostsolveMatrix::basic);
354                 
355                  sol[ithis]=clo2;
356                } else {
357                  /* no good */
358                  continue;
359                }
360              }
361            } else {
362              /* ilast ranged */
363              if (clo2<-1.0e20) {
364                // ithis has no lb
365                if (dcost2>dcost1) {
366                  //PRESOLVE_STMT(printf("DUPCOL3 (%d,%d)\n", ithis, ilast));
367                  /* set ilast to upper bound */
368                  fixed_up[nfixed_up++] = ilast;
369                  sort[jj] = ithis;
370                  sol[ithis] = newSolution;
371                  if (prob->getColumnStatus(ithis)==PrePostsolveMatrix::basic||
372                      prob->getColumnStatus(ilast)==PrePostsolveMatrix::basic)
373                    prob->setColumnStatus(ithis,PrePostsolveMatrix::basic);
374                 
375                  sol[ilast]=clo1;
376                } else {
377                  /* need both */
378                  continue;
379                }
380              } else if (cup2>1.0e20) {
381                if (dcost2<dcost1) {
382                  //PRESOLVE_STMT(printf("DUPCOL4 (%d,%d)\n", ithis, ilast));
383                  /* set ilast to lower bound */
384                  //SWAP(int, ilast, ithis);
385                  fixed_down[nfixed_down++] = ilast;
386                  sort[jj] = ithis;
387                  sol[ithis] = newSolution;
388                  if (prob->getColumnStatus(ithis)==PrePostsolveMatrix::basic||
389                      prob->getColumnStatus(ilast)==PrePostsolveMatrix::basic)
390                    prob->setColumnStatus(ithis,PrePostsolveMatrix::basic);
391                 
392                  sol[ilast]=clo1;
393                } else {
394                  /* need both */
395                  continue;
396                }
397              } else {
398                /* both ranged - no hope */
399                continue;
400              }
401            }
402          }
403        }
404      }
405    }
406  }
407
408  delete[]workrow;
409  delete[]workcol;
410  delete[]sort;
411
412
413  if (nactions) {
414#if     PRESOLVE_SUMMARY
415    printf("DUPLICATE COLS:  %d\n", nactions);
416#endif
417    next = new dupcol_action(nactions, copyOfArray(actions,nactions), next);
418  }
419  deleteAction(actions,action*);
420  if (nfixed_down)
421    next = make_fixed_action::presolve(prob, fixed_down, nfixed_down,
422                                       true,
423                                       next);
424
425  if (nfixed_up)
426    next = make_fixed_action::presolve(prob, fixed_up, nfixed_up,
427                                       false,
428                                       next);
429
430  delete[]fixed_down;
431  delete[]fixed_up;
432
433  return (next);
434}
435
436void create_col(int col, int n, int *rows, double *els,
437                CoinBigIndex *mcstrt, double *colels, int *hrow, int *link,
438                CoinBigIndex *free_listp)
439{
440  CoinBigIndex free_list = *free_listp;
441  int xstart = NO_LINK;
442  for (int i=0; i<n; ++i) {
443    CoinBigIndex k = free_list;
444    free_list = link[free_list];
445
446    check_free_list(free_list);
447
448    hrow[k]   = rows[i];
449    colels[k] = els[i];
450    link[k] = xstart;
451    xstart = k;
452  }
453  mcstrt[col] = xstart;
454  *free_listp = free_list;
455}
456
457
458void dupcol_action::postsolve(PostsolveMatrix *prob) const
459{
460  const action *const actions = actions_;
461  const int nactions = nactions_;
462
463  double *clo   = prob->clo_;
464  double *cup   = prob->cup_;
465
466  double *sol   = prob->sol_;
467  double *dcost = prob->cost_;
468 
469  double *colels        = prob->colels_;
470  int *hrow             = prob->hrow_;
471  CoinBigIndex *mcstrt          = prob->mcstrt_;
472  int *hincol           = prob->hincol_;
473  int *link             = prob->link_;
474
475  double *rcosts        = prob->rcosts_;
476
477  CoinBigIndex free_list                = prob->free_list_;
478
479  for (const action *f = &actions[nactions-1]; actions<=f; f--) {
480    int icol  = f->ithis;       // was fixed
481    int icol2 = f->ilast;       // was kept
482
483    dcost[icol] = dcost[icol2];
484    clo[icol] = f->thislo;
485    cup[icol] = f->thisup;
486    clo[icol2] = f->lastlo;
487    cup[icol2] = f->lastup;
488
489    create_col(icol, f->nincol, f->colrows, f->colels,
490               mcstrt, colels, hrow, link, &free_list);
491    hincol[icol] = hincol[icol2]; // right?
492
493    int nfinite = ((fabs(f->thislo) < PRESOLVE_INF) +
494                   (fabs(f->thisup) < PRESOLVE_INF) +
495                   (fabs(f->lastlo) < PRESOLVE_INF) +
496                   (fabs(f->lastup) < PRESOLVE_INF));
497
498    if (nfinite > 1) {
499       //      double l_j = f->thislo;
500      double u_j = f->thisup;
501      double l_k = f->lastlo;
502      double u_k = f->lastup;
503      double x_k_sol = sol[icol2];
504
505      prob->setColumnStatus(icol,prob->getColumnStatus(icol2));
506      if (x_k_sol <= l_k + u_j) {
507        sol[icol2] = l_k;
508        sol[icol] = x_k_sol - l_k;
509        prob->setColumnStatus(icol2,PrePostsolveMatrix::atLowerBound);
510      } else {
511        sol[icol2] = u_k;
512        sol[icol] = x_k_sol - u_k;
513        prob->setColumnStatus(icol2,PrePostsolveMatrix::atLowerBound);
514      }
515    } else if (nfinite == 1) {
516      double x_k_sol = sol[icol2];
517
518      if (fabs(f->thislo) < PRESOLVE_INF) {
519        prob->setColumnStatus(icol,PrePostsolveMatrix::atLowerBound);
520        sol[icol] = f->thislo;
521        sol[icol2] = x_k_sol - sol[icol];
522      } else if (fabs(f->thisup) < PRESOLVE_INF) {
523        prob->setColumnStatus(icol,PrePostsolveMatrix::atUpperBound);
524        sol[icol] = f->thisup;
525        sol[icol2] = x_k_sol - sol[icol];
526      } else if (fabs(f->lastlo) < PRESOLVE_INF) {
527        prob->setColumnStatus(icol,prob->getColumnStatus(icol2));
528        prob->setColumnStatus(icol2,PrePostsolveMatrix::atLowerBound);
529        sol[icol2] = f->lastlo;
530        sol[icol] = x_k_sol - sol[icol2];
531      } else {
532        // (fabs(f->lastup) < PRESOLVE_INF)
533        prob->setColumnStatus(icol,prob->getColumnStatus(icol2));
534        prob->setColumnStatus(icol2,PrePostsolveMatrix::atUpperBound);
535        sol[icol2] = f->lastup;
536        sol[icol] = x_k_sol - sol[icol2];
537      }
538    } else {
539      // both free!  superbasic time
540      sol[icol] = 0.0;  // doesn't matter
541      prob->setColumnStatus(icol2,PrePostsolveMatrix::isFree);
542    }
543
544    // row activity doesn't change
545    // dj of both variables is the same
546    rcosts[icol] = rcosts[icol2];
547
548#ifdef DEBUG_PRESOLVE
549    const double ztolzb = prob->ztolzb_;
550    if (! (clo[icol] - ztolzb <= sol[icol] && sol[icol] <= cup[icol] + ztolzb))
551             printf("BAD DUPCOL BOUNDS:  %g %g %g\n", clo[icol], sol[icol], cup[icol]);
552    if (! (clo[icol2] - ztolzb <= sol[icol2] && sol[icol2] <= cup[icol2] + ztolzb))
553             printf("BAD DUPCOL BOUNDS:  %g %g %g\n", clo[icol2], sol[icol2], cup[icol2]);
554#endif
555  }
556  prob->free_list_ = free_list;
557}
558
559
560
561
562
563// This is just ekkredc4, adapted into the new framework.
564const PresolveAction *duprow_action::presolve(PresolveMatrix *prob,
565                                               const PresolveAction *next)
566{
567   //  double *colels   = prob->colels_;
568  int *hrow             = prob->hrow_;
569  //  CoinBigIndex *mcstrt              = prob->mcstrt_;
570  //  int *hincol               = prob->hincol_;
571  int ncols             = prob->ncols_;
572
573  //  double *clo       = prob->clo_;
574  //  double *cup       = prob->cup_;
575
576  double *rowels        = prob->rowels_;
577  /*const*/ int *hcol   = prob->hcol_;
578  const CoinBigIndex *mrstrt    = prob->mrstrt_;
579  int *hinrow           = prob->hinrow_;
580  int nrows             = prob->nrows_;
581
582  double *rlo   = prob->rlo_;
583  double *rup   = prob->rup_;
584
585  //  const char *integerType = prob->integerType_;
586
587  //  double maxmin     = prob->maxmin_;
588
589  action *actions       = new action [nrows];
590  int nactions = 0;
591
592  double * workcol = new double[ncols];
593  double * workrow = new double[nrows];
594  int * sort = new int[nrows];
595
596  init_random_vec(workcol, ncols);
597
598  int nlook = compute_sums(hinrow, mrstrt, hcol, rowels, workcol, workrow, sort, nrows);
599#if 0
600  nlook=0;
601  for (i = 1; i <= nrow; ++i) {
602    if (mpre[i] == 0) {
603      double value=0.0;
604      CoinBigIndex krs=mrstrt[i];
605      CoinBigIndex kre=mrstrt[i+1];
606      CoinSort_2(hcol+krs,hcol+kre,dels+krs);
607      //ekk_sort2(hcol+krs,dels+krs,kre-krs);
608      for (k=krs;k<kre;k++) {
609        int icol=hcol[k];
610        value += workcol[icol]*dels[k];
611      }
612      workrow[nlook]=value;
613      sort[nlook++]=i;
614    }
615  }
616#endif
617  CoinSort_2(workrow,workrow+nlook,sort);
618  //ekk_sortonDouble(workrow,sort,nlook);
619
620  double dval = workrow[0];
621  for (int jj = 1; jj < nlook; jj++) {
622    if (workrow[jj]==dval) {
623      int ithis=sort[jj];
624      int ilast=sort[jj-1];
625      CoinBigIndex krs = mrstrt[ithis];
626      CoinBigIndex kre = krs + hinrow[ithis];
627      //      int ishift = mrstrt[ilast];
628      if (hinrow[ithis] == hinrow[ilast]) {
629        int ishift = mrstrt[ilast] - krs;
630        CoinBigIndex k;
631        for (k=krs;k<kre;k++) {
632          if (hcol[k] != hrow[k+ishift] ||
633              rowels[k] != rowels[k+ishift]) {
634            break;
635          }
636        }
637        if (k == kre) {
638          /* now check rhs to see what is what */
639          double rlo1=rlo[ilast];
640          double rup1=rup[ilast];
641          double rlo2=rlo[ithis];
642          double rup2=rup[ithis];
643
644          int idelete=0;
645          if (rlo1<rlo2) {
646            if (rup2<=rup1) {
647              /* this is strictly tighter than last */
648              idelete=ilast;
649            } else {
650              /* overlapping - could merge */
651#ifdef PRINT_DEBUG
652              printf("overlapping duplicate row %g %g, %g %g\n",
653                     rlo1,rup1,rlo2,rup2);
654#endif
655            }
656          } else {
657            // rlo2<=rlo1
658            if (rup1<=rup2) {
659              /* last is strictly tighter than this */
660              idelete=ithis;
661            } else {
662              /* overlapping - could merge */
663#ifdef PRINT_DEBUG
664              printf("overlapping duplicate row %g %g, %g %g\n",
665                     rlo1,rup1,rlo2,rup2);
666#endif
667            }
668          }
669          if (idelete) {
670            {
671              action *s = &actions[nactions];     
672              nactions++;
673
674              s->row    = idelete;
675              s->lbound = rlo[idelete];
676              s->ubound = rup[idelete];
677            }
678            // lazy way - let some other transform eliminate the row
679            rup[idelete] = PRESOLVE_INF;
680            rlo[idelete] = PRESOLVE_INF;
681
682            nactions++;
683          }
684        }
685      }
686    }
687    dval=workrow[jj];
688  }
689
690  delete[]workrow;
691  delete[]workcol;
692  delete[]sort;
693
694
695  if (nactions) {
696#if     PRESOLVE_SUMMARY
697    printf("DUPLICATE ROWS:  %d\n", nactions);
698#endif
699    next = new duprow_action(nactions, copyOfArray(actions,nactions), next);
700  }
701  deleteAction(actions,action*);
702  return (next);
703}
704
705void duprow_action::postsolve(PostsolveMatrix *prob) const
706{
707  printf("STILL NO POSTSOLVE FOR DUPROW!\n");
708  abort();
709}
Note: See TracBrowser for help on using the repository browser.