Example #1
0
/* Do a generic readable data dump of key lp_solve model variables;
   principally for run difference and debugging purposes */
MYBOOL REPORT_debugdump(lprec *lp, char *filename, MYBOOL livedata)
{
    /* FILE   *output = stdout; */
    FILE   *output;
    MYBOOL ok;

    ok = (MYBOOL) ((filename == NULL) || ((output = fopen(filename,"w")) != NULL));
    if(!ok)
        return(ok);
    if((filename == NULL) && (lp->outstream != NULL))
        output = lp->outstream;

    fprintf(output, "\nGENERAL INFORMATION\n-------------------\n\n");
    fprintf(output, "Model size:     %d rows (%d equalities, %d Lagrangean), %d columns (%d integers, %d SC, %d SOS, %d GUB)\n",
            lp->rows, lp->equalities, get_Lrows(lp), lp->columns,
            lp->int_vars, lp->sc_vars, SOS_count(lp), GUB_count(lp));
    fprintf(output, "Data size:      %d model non-zeros, %d invB non-zeros (engine is %s)\n",
            get_nonzeros(lp), my_if(lp->invB == NULL, 0, lp->bfp_nonzeros(lp, FALSE)), lp->bfp_name());
    fprintf(output, "Internal sizes: %d rows allocated, %d columns allocated, %d columns used, %d eta length\n",
            lp->rows_alloc, lp->columns_alloc, lp->columns, my_if(lp->invB == NULL, 0, lp->bfp_colcount(lp)));
    fprintf(output, "Memory use:     %d sparse matrix, %d eta\n",
            lp->matA->mat_alloc, my_if(lp->invB == NULL, 0, lp->bfp_memallocated(lp)));
    fprintf(output, "Parameters:     Maximize=%d, Names used=%d, Scalingmode=%d, Presolve=%d, SimplexPivot=%d\n",
            is_maxim(lp), lp->names_used, lp->scalemode, lp->do_presolve, lp->piv_strategy);
    fprintf(output, "Precision:      EpsValue=%g, EpsPrimal=%g, EpsDual=%g, EpsPivot=%g, EpsPerturb=%g\n",
            lp->epsvalue, lp->epsprimal, lp->epsdual, lp->epspivot, lp->epsperturb);
    fprintf(output, "Stability:      AntiDegen=%d, Improvement=%d, Split variables at=%g\n",
            lp->improve, lp->anti_degen, lp->negrange);
    fprintf(output, "B&B settings:   BB pivot rule=%d, BB branching=%s, BB strategy=%d, Integer precision=%g, MIP gaps=%g,%g\n",
            lp->bb_rule, my_boolstr(lp->bb_varbranch), lp->bb_floorfirst, lp->epsint, lp->mip_absgap, lp->mip_relgap);

    fprintf(output, "\nCORE DATA\n---------\n\n");
    blockWriteINT(output,  "Column starts", lp->matA->col_end, 0, lp->columns);
    blockWriteINT(output,  "row_type", lp->row_type, 0, lp->rows);
    blockWriteREAL(output, "orig_rhs", lp->orig_rhs, 0, lp->rows);
    blockWriteREAL(output, "orig_lowbo", lp->orig_lowbo, 0, lp->sum);
    blockWriteREAL(output, "orig_upbo", lp->orig_upbo, 0, lp->sum);
    blockWriteINT(output,  "row_type", lp->row_type, 0, lp->rows);
    blockWriteBOOL(output, "var_type", lp->var_type, 0, lp->columns, TRUE);
    blockWriteAMAT(output, "A", lp, 0, lp->rows);

    if(livedata) {
        fprintf(output, "\nPROCESS DATA\n------------\n\n");
        blockWriteREAL(output,  "Active rhs", lp->rhs, 0, lp->rows);
        blockWriteINT(output,  "Basic variables", lp->var_basic, 0, lp->rows);
        blockWriteBOOL(output, "is_basic", lp->is_basic, 0, lp->sum, TRUE);
        blockWriteREAL(output, "lowbo", lp->lowbo, 0, lp->sum);
        blockWriteREAL(output, "upbo", lp->upbo, 0, lp->sum);
        if(lp->scalars != NULL)
            blockWriteREAL(output, "scalars", lp->scalars, 0, lp->sum);
    }

    if(filename != NULL)
        fclose(output);
    return(ok);
}
Example #2
0
STATIC REAL getPricer(lprec *lp, int item, MYBOOL isdual)
{
  REAL value = 1.0;

  if(!applyPricer(lp))
    return( value );

  value = *lp->edgeVector;

  /* Make sure we have a price vector to use */
  if(value < 0) {
#ifdef Paranoia
    report(lp, SEVERE, "getPricer: Called without having being initialized!\n");
#endif
    return( 1.0 );
  }
  /* We may be calling the primal from the dual (and vice-versa) for validation
     of feasibility; ignore calling origin and simply return 1 */
  else if(isdual != value) {
    return( 1.0 );
  }
  /* Do the normal norm retrieval */
  else {

    if(isdual)
      item = lp->var_basic[item];

    value = lp->edgeVector[item];

    if(value == 0) {
      value = 1.0;
      report(lp, SEVERE, "getPricer: Detected a zero-valued price at index %d\n", item);
    }
#ifdef Paranoia
    else if(value < 0)
      report(lp, SEVERE, "getPricer: Invalid %s reduced cost norm %g at index %d\n",
                          my_if(isdual, "dual", "primal"), value, item);
#endif

  /* Return the norm */
    return( sqrt(value) );
  }
}
Example #3
0
void REPORT_modelinfo(lprec *lp, MYBOOL doName, char *datainfo)
{
  if(doName) {
    report(lp, NORMAL, "\nModel name:  '%s' - run #%-5d\n",
                       get_lp_name(lp), lp->solvecount);
    report(lp, NORMAL, "Objective:   %simize(%s)\n",
                       my_if(is_maxim(lp), "Max", "Min"), get_row_name(lp, 0));
    report(lp, NORMAL, " \n");
  }
  if(datainfo != NULL)
    report(lp, NORMAL, "%s\n", datainfo);

  report(lp, NORMAL, "Model size:  %7d constraints, %7d variables, %12d non-zeros.\n",
         lp->rows, lp->columns, get_nonzeros(lp));
  if(GUB_count(lp)+SOS_count(lp) > 0)
  report(lp, NORMAL, "Var-types:   %7d integer,     %7d semi-cont.,     %7d SOS.\n",
         lp->int_vars, lp->sc_vars, lp->sos_vars);
  report(lp, NORMAL, "Sets:                             %7d GUB,            %7d SOS.\n",
                         GUB_count(lp), SOS_count(lp));
}
Example #4
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 {
Example #5
0
STATIC int primloop(lprec *lp, MYBOOL feasible)
{
  int     i, j, k, ok = TRUE;
  LREAL  theta = 0.0;
  REAL   *prow = NULL, *drow = NULL, *pcol = NULL, prevobj, epsvalue;
  MYBOOL primal = TRUE, minit;
  MYBOOL pivdynamic, bfpfinal = FALSE;
  int    oldpivrule, oldpivmode, pivrule, Blandswitches,
         colnr, rownr, lastnr, minitcount = 0;
  int    Rcycle = 0, Ccycle = 0, Ncycle = 0, changedphase = FALSE;
  int    *nzdrow = NULL, *workINT = NULL;

 /* Add sufficent number of artificial variables to make the problem feasible
    through the first phase; delete when primal feasibility has been achieved */
  lp->Extrap = 0;
#ifdef EnablePrimalPhase1
  if(!feasible) {
#ifdef Paranoia
    if(!verifyBasis(lp))
      report(lp, SEVERE, "primloop: No valid basis for artificial variables\n");
#endif
#if 0
    /* First check if we can get away with a single artificial variable */
    if(lp->equalities == 0) {
      i = (int) feasibilityOffset(lp, !primal);
      add_artificial(lp, i);
    }
    else
#endif
    /* Otherwise add as many as is necessary to force basic feasibility */
      for(i = 1; i <= lp->rows; i++)
        add_artificial(lp, i);
  }
  if(lp->spx_trace)
    report(lp, DETAILED, "Extrap count = %d\n", lp->Extrap);
#endif

  if(lp->spx_trace)
    report(lp, DETAILED, "Entered primal simplex algorithm with feasibility %s\n",
                         my_boolstr(feasible));

 /* Create work arrays */
#ifdef UseSparseReducedCost
  allocINT(lp, &nzdrow, lp->sum + 1, FALSE);
#endif
  allocREAL(lp, &prow, lp->sum + 1, TRUE);
  allocREAL(lp, &drow, 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_PRIMAL) && !lp->justInverted) ||
     (lp->Extrap != 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 = 0;
  lastnr = 0;
  lp->rejectpivot[0] = 0;
  if(feasible)
    lp->simplex_mode = SIMPLEX_Phase2_PRIMAL;
  else
    lp->simplex_mode = SIMPLEX_Phase1_PRIMAL;

 /* Iterate while we are successful; exit when the model is infeasible/unbounded,
    or we must terminate due to numeric instability or user-determined reasons */
  while(lp->spx_status == RUNNING) {

    if(lp->spx_trace)
      if(lastnr > 0)
      report(lp, NORMAL, "primloop: 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 PrimalPivotStickiness==2
       && (lp->fixedvars == 0)
#elif PrimalPivotStickiness==1
       && 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, "primloop: Detected cycling at iteration %d; changed to FIRST INDEX rule!\n",
                                 get_total_iter(lp));
        }
      }
#if 0
      /* Handle cycling or stationary situations by switching to the dual simplex */
      else if((pivrule == oldpivrule) && feasible && (lp->simplex_strategy & SIMPLEX_DYNAMIC)) {
        lp->spx_status = SWITCH_TO_DUAL;
        if(lp->total_iter == 0)
          report(lp, NORMAL, "Start dual simplex for finalization at iteration  %8d\n",
                             get_total_iter(lp));
        break;
      }
#endif
      /* 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 */
    prevobj = lp->rhs[0];

    lp->doIterate = FALSE;
    lp->doInvert = FALSE;

   /* Find best column to enter the basis */
RetryCol:
    if(!changedphase) {
      i = 0;
      do {
        if(partial_countBlocks(lp, (MYBOOL) !primal) > 1)
          partial_blockStep(lp, (MYBOOL) !primal);
        colnr = colprim(lp, (MYBOOL) (minit == ITERATE_MINORRETRY), drow, nzdrow);
        i++;
      } while ((colnr == 0) && (i < partial_countBlocks(lp, (MYBOOL) !primal)));

#ifdef FinalOptimalErrorLimitation
      /* Do additional checking that we have a correct identification of optimality */
      if((colnr == 0) && !lp->justInverted) {
        lp->doInvert = TRUE;
        i = invert(lp, INITSOL_USEZERO, TRUE);
        colnr = colprim(lp, FALSE, drow, nzdrow);
      }
#endif
    }

    if(colnr > 0) {
      changedphase = FALSE;
      fsolve(lp, colnr, pcol, workINT, lp->epsmachine, 1.0, TRUE);   /* Solve entering column for Pi */
#ifdef UseRejectionList
      if(is_anti_degen(lp, ANTIDEGEN_COLUMNCHECK) && !check_degeneracy(lp, pcol, NULL)) {
        if(lp->rejectpivot[0] < DEF_MAXPIVOTRETRY/3) {
          i = ++lp->rejectpivot[0];
          lp->rejectpivot[i] = colnr;
          report(lp, DETAILED, "Entering column %d found to be non-improving due to degeneracy!\n",
                     colnr);
          goto RetryCol;
        }
        else {
          lp->rejectpivot[0] = 0;
          report(lp, DETAILED, "Gave up trying to find a strictly improving entering column!\n");
        }
      }
#endif

      /* Find the leaving variable that gives the most stringent bound on the entering variable */
      theta = drow[colnr];
      rownr = rowprim(lp, colnr, &theta, pcol);
#if 0
      report(lp, NORMAL, "Iteration %d: Enter %d, Leave %d\n", lp->current_iter, colnr, rownr);
#endif

      /* See if we can do a straight artificial<->slack replacement (when "colnr" is a slack) */
      if((lp->Extrap != 0) && (rownr == 0) && (colnr <= lp->rows))
        rownr = findAnti_artificial(lp, colnr);

      if(rownr > 0) {
        lp->rejectpivot[0] = 0;
        lp->bfp_prepareupdate(lp, rownr, colnr, pcol);
      }
      else if(lp->spx_status == UNBOUNDED) {
        report(lp, DETAILED, "primloop: The model is primal unbounded.\n");
        break;
      }
#ifdef UseRejectionList
      else if(lp->rejectpivot[0] < DEF_MAXPIVOTRETRY) {
        lp->spx_status = RUNNING;
        if(lp->justInverted) {
          lp->rejectpivot[0]++;
          lp->rejectpivot[lp->rejectpivot[0]] = colnr;
          report(lp, DETAILED, "...trying to recover via another pivot column!\n");
        }
        else {
          lp->doInvert = TRUE;
          invert(lp, INITSOL_USEZERO, TRUE);
        }
        goto RetryCol;
      }
#endif
      else {

        /* Assume failure if we are still unsuccessful and the model is not unbounded */
        if((rownr == 0) && (lp->spx_status == RUNNING)) {
          report(lp, IMPORTANT, "primloop: Could not find a leaving variable for entering %d (iteration %d)\n",
                                 colnr, get_total_iter(lp));
          lp->spx_status = NUMFAILURE;
        }
      }
    }
#ifdef EnablePrimalPhase1
    else if(!feasible || isPhase1(lp)) {

      if(feasiblePhase1(lp, epsvalue)) {
        lp->spx_status = RUNNING;
        if(lp->bb_totalnodes == 0) {
          report(lp, NORMAL, "Found feasibility by primal simplex at iteration  %8d\n",
                              get_total_iter(lp));
          if((lp->usermessage != NULL) && (lp->msgmask & MSG_LPFEASIBLE))
            lp->usermessage(lp, lp->msghandle, MSG_LPFEASIBLE);
        }
        changedphase = FALSE;
        feasible = TRUE;
        lp->simplex_mode = SIMPLEX_Phase2_PRIMAL;

       /* We can do two things now;
          1) delete the rows belonging to those variables, since they are redundant, OR
          2) drive out the existing artificial variables via pivoting. */
        if(lp->Extrap > 0) {

#ifdef Phase1EliminateRedundant
         /* If it is not a MIP model we can try to delete redundant rows */
          if((lp->bb_totalnodes == 0) && (MIP_count(lp) == 0)) {
            while(lp->Extrap > 0) {
              i = lp->rows;
              while((i > 0) && (lp->var_basic[i] <= lp->sum-lp->Extrap))
                i--;
#ifdef Paranoia
              if(i <= 0) {
                report(lp, SEVERE, "primloop: Could not find redundant artificial.\n");
                break;
              }
#endif
              /* Obtain column and row indeces */
              j = lp->var_basic[i]-lp->rows;
              k = get_artificialRow(lp, j);

              /* Delete row before column due to basis "compensation logic" */
              if(lp->is_basic[k]) {
                lp->is_basic[lp->rows+j] = FALSE;
                del_constraint(lp, k);
              }
              else
                setBasisVar(lp, i, k);
              del_column(lp, j);
              lp->Extrap--;
            }
            lp->basis_valid = TRUE;
          }
         /* Otherwise we drive out the artificials by elimination pivoting */
          else {
            eliminate_artificials(lp, prow);
            lp->doIterate = FALSE;
          }
#else
          lp->Extrap = my_flipsign(lp->Extrap);
#endif
        }
        lp->doInvert = TRUE;
        prevobj = lp->infinite;
      }
      else {
        lp->spx_status = INFEASIBLE;
        minit = ITERATE_MAJORMAJOR;
        if(lp->spx_trace)
          report(lp, NORMAL, "Model infeasible by primal simplex at iteration   %8d\n",
                             get_total_iter(lp));
      }
    }
#endif

    /* Pivot row/col and update the inverse */
    if(lp->doIterate) {
      lastnr = lp->var_basic[rownr];

      if(lp->justInverted)
        minitcount = 0;
      else if(minitcount > MAX_MINITUPDATES) {
        recompute_solution(lp, INITSOL_USEZERO);
        minitcount = 0;
      }
      minit = performiteration(lp, rownr, colnr, theta, primal, NULL, NULL,
                                                                pcol, NULL);
      if(minit != ITERATE_MAJORMAJOR)
        minitcount++;

      if((lp->spx_status == USERABORT) || (lp->spx_status == TIMEOUT))
        break;
      else if(minit == ITERATE_MINORMAJOR)
        continue;
#ifdef UsePrimalReducedCostUpdate
      /* Do a fast update of the reduced costs in preparation for the next iteration */
      if(minit == ITERATE_MAJORMAJOR)
        update_reducedcosts(lp, primal, lastnr, colnr, pcol, drow);
#endif

#ifdef EnablePrimalPhase1
      /* Detect if an auxiliary variable has left the basis and delete it; if
         the non-basic variable only changed bound (a "minor iteration"), the
         basic artificial variable did not leave and there is nothing to do */
      if((minit == ITERATE_MAJORMAJOR) && (lastnr > lp->sum - abs(lp->Extrap))) {
#ifdef Paranoia
        if(lp->is_basic[lastnr] || !lp->is_basic[colnr])
          report(lp, SEVERE, "primloop: Invalid basis indicator for variable %d at iteration %d\n",
                              lastnr, get_total_iter(lp));
#endif
        del_column(lp, lastnr-lp->rows);
        if(lp->Extrap > 0)
          lp->Extrap--;
        else
          lp->Extrap++;
        if(lp->Extrap == 0) {
          colnr = 0;
          prevobj = lp->infinite;
          changedphase = TRUE;
        }
      }

#endif
    }

    if(lp->spx_status == SWITCH_TO_DUAL)
      ;
    else if(!changedphase && lp->bfp_mustrefactorize(lp)) {
      i = invert(lp, INITSOL_USEZERO, FALSE);
#ifdef ResetMinitOnReinvert
      minit = ITERATE_MAJORMAJOR;
#endif

      if((lp->spx_status == USERABORT) || (lp->spx_status == TIMEOUT))
        break;
      else if(!i) {
        lp->spx_status = SINGULAR_BASIS;
        break;
      }
      /* Check whether we are still feasible or not... */
      if(!isPrimalFeasible(lp, lp->epspivot)) {
        lp->spx_status = LOSTFEAS;
      }
    }
    userabort(lp, -1);

  }
  if (lp->piv_strategy != oldpivmode)
    lp->piv_strategy = oldpivmode;

#ifdef EnablePrimalPhase1

  /* Remove any remaining artificial variables (feasible or infeasible model) */
  lp->Extrap = abs(lp->Extrap);
  if(lp->Extrap > 0) {
    clear_artificials(lp);
    if(lp->spx_status != OPTIMAL)
      restore_basis(lp);
    i = invert(lp, INITSOL_USEZERO, TRUE);
  }
#ifdef Paranoia
  if(!verifyBasis(lp))
    report(lp, SEVERE, "primloop: Invalid basis detected due to internal error\n");
#endif

  /* Switch to dual phase 1 simplex for MIP models during B&B phases */
  if((lp->bb_totalnodes == 0) && (MIP_count(lp) > 0) &&
     ((lp->simplex_strategy & SIMPLEX_Phase1_DUAL) == 0)) {
    lp->simplex_strategy &= !SIMPLEX_Phase1_PRIMAL;
    lp->simplex_strategy += SIMPLEX_Phase1_DUAL;
  }

#endif

  FREE(nzdrow);
  FREE(drow);
  FREE(prow);
  FREE(pcol);

  return(ok);
} /* primloop */