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