void compute_thvec(void)  /* simplest model */
{
    compute_theta( nvec,xvec,yvec , ctvec,stvec ) ;
}
compute_thvim(void)
{
    compute_theta( nvim,xvim,yvim , ctvim,stvim ) ;
}
Esempio n. 3
0
STATIC int dualloop(lprec *lp, MYBOOL feasible)
{
  int    i, ok = TRUE;
  LREAL  theta = 0.0;
  REAL   *drow = NULL, *prow = NULL, *pcol = NULL, prevobj, epsvalue;
  MYBOOL primal = FALSE, forceoutEQ = FALSE;
  MYBOOL minit, pivdynamic, bfpfinal = FALSE;
  int    oldpivrule, oldpivmode, pivrule, Blandswitches,
         colnr, rownr, lastnr, minitcount = 0;
  int    Rcycle = 0, Ccycle = 0, Ncycle = 0, changedphase = TRUE;
#ifdef FixInaccurateDualMinit
  int    minitcolnr = 0;
#endif
  int    *nzprow = NULL, *workINT = NULL;

  if(lp->spx_trace)
    report(lp, DETAILED, "Entering dual simplex algorithm\n");

 /* Set Extrad value to force dual feasibility; reset when
    "local optimality" has been achieved or a dual non-feasibility
    has been encountered (no candidate for a first leaving variable) */
  if(feasible)
    lp->Extrad = 0;
  else
    lp->Extrad = feasibilityOffset(lp, (MYBOOL)!primal);

  if(lp->spx_trace)
    report(lp, DETAILED, "Extrad = %g\n", (double)lp->Extrad);

 /* Allocate work arrays */
  allocREAL(lp, &drow, lp->sum + 1, TRUE);
#ifdef UseSparseReducedCost
  allocINT(lp, &nzprow, lp->sum + 1, FALSE);
#endif
  allocREAL(lp, &prow, lp->sum + 1, TRUE);
  allocREAL(lp, &pcol, lp->rows + 1, TRUE);

 /* Refactorize the basis and set status variables */
  i = my_if(is_bb_action(lp, ACTION_REBASE), INITSOL_SHIFTZERO, INITSOL_USEZERO);
  if(((lp->spx_status == SWITCH_TO_DUAL) && !lp->justInverted) ||
     (lp->Extrad != 0) ||
     is_bb_action(lp, ACTION_REINVERT)) {
    simplexPricer(lp, (MYBOOL)!primal);

    /* Do basis crashing before refactorization, if specified */
    invert(lp, (MYBOOL) i, TRUE);
  }
  else {
    if(is_bb_action(lp, ACTION_RECOMPUTE))
      recompute_solution(lp, (MYBOOL) i);
    restartPricer(lp, (MYBOOL)!primal);
  }
  lp->bb_action = ACTION_NONE;

  lp->spx_status = RUNNING;
  lp->doIterate = FALSE;
  minit = ITERATE_MAJORMAJOR;
  prevobj = lp->rhs[0];
  oldpivmode = lp->piv_strategy;
  oldpivrule = get_piv_rule(lp);
  pivdynamic = ANTICYCLEBLAND && is_piv_mode(lp, PRICE_ADAPTIVE);
  epsvalue = lp->epspivot;
  Blandswitches = 0;
  rownr = 0;
  colnr = -1;  /* Used to detect infeasibility at the beginning of the dual loop */
  lastnr = 0;
  lp->rejectpivot[0] = 0;
  if(feasible)
    lp->simplex_mode = SIMPLEX_Phase2_DUAL;
  else
    lp->simplex_mode = SIMPLEX_Phase1_DUAL;

  /* Check if we have equality slacks in the basis and we should try to
     drive them out in order to reduce chance of degeneracy in Phase 1 */
  if(!feasible && (lp->fixedvars > 0) && is_anti_degen(lp, ANTIDEGEN_FIXEDVARS)) {
    forceoutEQ = AUTOMATIC;
  }

  while(lp->spx_status == RUNNING) {

    if(lp->spx_trace)
      if(lastnr > 0)
      report(lp, NORMAL, "dualloop: Objective at iteration %8d is " RESULTVALUEMASK " (%4d: %4d %s- %4d)\n",
                         get_total_iter(lp), lp->rhs[0], rownr, lastnr,
                         my_if(minit == ITERATE_MAJORMAJOR, "<","|"), colnr);

    pivrule = get_piv_rule(lp);
    if(pivdynamic && ((pivrule != PRICER_FIRSTINDEX) ||
                      (pivrule != oldpivrule))
#if DualPivotStickiness==2
      /* Stays with pricing rule as long as possible (also preserves accuracy) */
       && (lp->fixedvars == 0)
#elif DualPivotStickiness==1
      /* Stays with pricing rule only if the model is infeasible */
       && feasible
#endif
      ) {
      /* Check if we have a stationary solution */
      if((minit == ITERATE_MAJORMAJOR) && !lp->justInverted &&
         (fabs(my_reldiff(lp->rhs[0], prevobj)) < epsvalue)) {
        Ncycle++;
        /* Start to monitor for variable cycling if this is the initial stationarity */
        if(Ncycle <= 1) {
          Ccycle = colnr;
          Rcycle = rownr;
        }
        /* Check if we should change pivoting strategy due to stationary variable cycling */
        else if((pivrule == oldpivrule) && (((MAX_STALLCOUNT > 1) && (Ncycle > MAX_STALLCOUNT)) ||
                                            (Ccycle == rownr) || (Rcycle == colnr))) {
          /* First check if we should give up on Bland's rule and try perturbed bound
             relaxation instead */
#ifdef EnableStallAntiDegen
          if((MAX_BLANDSWITCH >= 0) && (Blandswitches >= MAX_BLANDSWITCH)) {
            lp->spx_status = DEGENERATE;
            break;
          }
#endif
          Blandswitches++;
          lp->piv_strategy = PRICER_FIRSTINDEX;  /* There is no advanced normalization for Bland's rule, restart at end */
          Ccycle = 0;
          Rcycle = 0;
          Ncycle = 0;
          if(lp->spx_trace)
            report(lp, DETAILED, "dualloop: Detected cycling at iteration %d; changed to FIRST INDEX rule!\n",
                                 get_total_iter(lp));
        }
      }
      /* Handle cycling or stationary situations by switching to the primal simplex */
      else if((pivrule == oldpivrule) && feasible && (lp->simplex_strategy & SIMPLEX_DYNAMIC)) {
        lp->spx_status = SWITCH_TO_PRIMAL;
        break;
      }
      /* Change back to original selection strategy as soon as possible */
      else if((minit == ITERATE_MAJORMAJOR) && (pivrule != oldpivrule)) {
        lp->piv_strategy = oldpivmode;
        restartPricer(lp, AUTOMATIC);    /* Pricer restart following Bland's rule */
        Ccycle = 0;
        Rcycle = 0;
        Ncycle = 0;
        if(lp->spx_trace)
          report(lp, DETAILED, "...returned to original pivot selection rule at iteration %d.\n",
                               get_total_iter(lp));
      }
    }

    /* Store current LP value for reference at next iteration */
    changedphase = FALSE;
    prevobj = lp->rhs[0];
    lastnr = lp->var_basic[rownr];
    lp->doInvert = FALSE;

    /* Do minor iterations (non-basic variable bound switches) for as
       long as possible since this is a cheap way of iterating */
#ifdef Phase1DualPriceEqualities
RetryRow:
#endif
    if(minit != ITERATE_MINORRETRY) {
      /* forceoutEQ
           FALSE : Only eliminate assured "good" violated equality constraint slacks
           AUTOMATIC: Seek more elimination of equality constraint slacks
                   (but not as aggressive as the rule used in lp_solve v4.0 and earlier)
           TRUE:   Force remaining equality slacks out of the basis */
      i = 0;
      do {
        if(partial_countBlocks(lp, (MYBOOL) !primal) > 1)
          partial_blockStep(lp, (MYBOOL) !primal);
        rownr = rowdual(lp, forceoutEQ);
        i++;
      } while ((rownr == 0) && (i < partial_countBlocks(lp, (MYBOOL) !primal)));

      lastnr = lp->var_basic[rownr];
    }

    if(rownr > 0) {
#ifdef UseRejectionList
RetryCol:
#endif
      lp->doIterate = FALSE;
      colnr = coldual(lp, rownr, (MYBOOL)(minit == ITERATE_MINORRETRY),
                          prow, nzprow, drow, NULL);
      if(colnr > 0) {
        lp->doIterate = TRUE;
        fsolve(lp, colnr, pcol, workINT, lp->epsmachine, 1.0, TRUE);

#ifdef FixInaccurateDualMinit
       /* Prevent bound flip-flops during minor iterations; used to detect
          infeasibility after triggering of minor iteration accuracy management */
        if(colnr != minitcolnr)
          minitcolnr = 0;
#endif

       /* Getting division by zero here; catch it and try to recover */
        if(pcol[rownr] == 0) {
          if(lp->spx_trace)
            report(lp, DETAILED, "dualloop: Attempt to divide by zero (pcol[%d])\n", rownr);
          lp->doIterate = FALSE;
          if(!lp->justInverted) {
            report(lp, DETAILED, "...trying to recover by reinverting!\n");
            lp->doInvert = TRUE;
            bfpfinal = FALSE;
          }
#ifdef UseRejectionList
          else if(lp->rejectpivot[0] < DEF_MAXPIVOTRETRY) {
            lp->rejectpivot[0]++;
            lp->rejectpivot[lp->rejectpivot[0]] = colnr;
            if(lp->bb_totalnodes == 0)
              report(lp, DETAILED, "...trying to recover via another pivot column!\n");
            goto RetryCol;
          }
#endif
          else {
            if(lp->bb_totalnodes == 0)
              report(lp, DETAILED, "...cannot recover by reinverting.\n");
            lp->spx_status = NUMFAILURE;
            ok = FALSE;
          }
        }
        else {
          lp->rejectpivot[0] = 0;
          theta = lp->bfp_prepareupdate(lp, rownr, colnr, pcol);


         /* Verify numeric accuracy of the inverse and change to
            the "theoretically" correct version of the theta */
          if((lp->improve & IMPROVE_INVERSE) &&
             (my_reldiff(fabs(theta),fabs(prow[colnr])) >
              lp->epspivot*10.0*log(2.0+50.0*lp->rows))) {
            lp->doInvert = TRUE;
            bfpfinal = TRUE;
#ifdef IncreasePivotOnReducedAccuracy
            if(lp->bfp_pivotcount(lp) < 2*DEF_MAXPIVOTRETRY)
              lp->epspivot *= 2.0;
#endif
            report(lp, DETAILED, "dualloop: Refactorizing at iteration %d due to loss of accuracy.\n",
                                 get_total_iter(lp));
          }
          theta = prow[colnr];
          compute_theta(lp, rownr, &theta, !lp->is_lower[colnr], 0, primal);
        }
      }
#ifdef FixInaccurateDualMinit
      /* Reinvert and try another row if we did not find a bound-violated leaving column */
      else if((minit != ITERATE_MAJORMAJOR) && (colnr != minitcolnr)) {
        minitcolnr = colnr;
        lp->doInvert = TRUE;
        i = invert(lp, INITSOL_USEZERO, TRUE);
        if((lp->spx_status == USERABORT) || (lp->spx_status == TIMEOUT))
          break;
        else if(!i) {
          lp->spx_status = SINGULAR_BASIS;
          break;
        }
        minit = ITERATE_MAJORMAJOR;
        continue;
      }
#endif
      else {
        if(lp->justInverted && (lp->simplex_mode == SIMPLEX_Phase2_DUAL))
          lp->spx_status = LOSTFEAS;
#if 1
        else if(!lp->justInverted && (lp->bb_level <= 1)) {
#else
        else if(!lp->justInverted) {
#endif
          lp->doIterate = FALSE;
          lp->doInvert = TRUE;
          bfpfinal = TRUE;
        }
        else {
          if((lp->spx_trace && (lp->bb_totalnodes == 0)) ||
             (lp->bb_trace && (lp->bb_totalnodes > 0)))
            report(lp, DETAILED, "Model lost dual feasibility.\n");
          lp->spx_status = INFEASIBLE;
          ok = FALSE;
          break;
        }
      }
    }
    else {

      /* New code to solve to optimality using the dual, but only if the user
         has specified a preference for the dual simplex - KE added 20030731 */
      lp->doIterate = FALSE;
      bfpfinal = TRUE;
      if((lp->Extrad != 0) && (colnr < 0) && !isPrimalFeasible(lp, lp->epsprimal)) {
        if(feasible) {
          if(lp->bb_totalnodes == 0)
            report(lp, DETAILED, "Model is dual infeasible and primal feasible\n");
          lp->spx_status = SWITCH_TO_PRIMAL;
          lp->doInvert = (MYBOOL) (lp->Extrad != 0);
          lp->Extrad = 0;
        }
        else {
          if(lp->bb_totalnodes == 0)
            report(lp, NORMAL, "Model is primal and dual infeasible\n");
          lp->spx_status = INFEASIBLE;
          ok = FALSE;
        }
        break;
      }
      else if(lp->Extrad == 0) {

        /* We are feasible (and possibly also optimal) */
        feasible = TRUE;
        lp->simplex_mode = SIMPLEX_Phase2_DUAL;

        /* Check if we still have equality slacks stuck in the basis; drive them out? */
        if((lp->fixedvars > 0) && lp->bb_totalnodes == 0)
#ifdef Paranoia
          report(lp, NORMAL,
#else
          report(lp, DETAILED,
#endif
                    "Found dual solution with %d fixed slack variables left basic\n",
                    lp->fixedvars);

#ifdef Phase1DualPriceEqualities
        if(forceoutEQ != TRUE) {
          forceoutEQ = TRUE;
          goto RetryRow;
        }
        colnr = 0;
#else

#if 1
       /* Problem: Check if we are dual degenerate and need to switch to the
          primal simplex (there is a flaw in the dual simplex code) */
        colnr = colprim(lp, FALSE, drow, nzprow);
#else
        colnr = 0;
#endif

#endif

        if(colnr == 0)
          lp->spx_status = OPTIMAL;
        else {
          lp->spx_status = SWITCH_TO_PRIMAL;
          if(lp->total_iter == 0)
            report(lp, NORMAL, "Use primal simplex for finalization at iteration  %8d\n",
                               get_total_iter(lp));
        }
        if((lp->total_iter == 0) && (lp->spx_status == OPTIMAL))
          report(lp, NORMAL,   "Optimal solution with dual simplex at iteration   %8d\n",
                             get_total_iter(lp));
        break;
      }
      else {