示例#1
0
STATIC MYBOOL scaleCR(lprec *lp, REAL *scaledelta)
{
  REAL *scalechange = NULL;
  int  Result;

  if(!lp->scaling_used) {
    allocREAL(lp, &lp->scalars, lp->sum_alloc + 1, FALSE);
    for(Result = 0; Result <= lp->sum; Result++)
      lp->scalars[Result] = 1;
    lp->scaling_used = TRUE;
  }

  if(scaledelta == NULL)
    allocREAL(lp, &scalechange, lp->sum + 1, FALSE);
  else
    scalechange = scaledelta;

  Result=CurtisReidScales(lp, FALSE, scalechange, &scalechange[lp->rows]);
  if(Result>0) {

    /* Do the scaling*/
    if(scale_updaterows(lp, scalechange, TRUE) ||
       scale_updatecolumns(lp, &scalechange[lp->rows], TRUE))
      lp->scalemode |= SCALE_CURTISREID;

    set_action(&lp->spx_action, ACTION_REBASE | ACTION_REINVERT | ACTION_RECOMPUTE);
  }

  if(scaledelta == NULL)
    FREE(scalechange);

  return((MYBOOL) (Result > 0));
}
示例#2
0
STATIC void formWeights(lprec *lp, int colnr, REAL *pcol, REAL **w)
/* This computes Bw = a, where B is the basis and a is a column of A */
{
  allocREAL(lp, w, lp->rows+1, FALSE);
  if(pcol == NULL)
    fsolve(lp, colnr, *w, NULL, 0.0, 0.0, FALSE);
  else {
    MEMCOPY(*w, pcol, lp->rows+1);
/*    *w[0] = 0; */ /* Test */
  }
/*
  if(pcol != NULL) {
    REAL cEdge, hold;
    int  i;

    cEdge = 0;
    for(i = 1; i <= m; i++) {
      hold = *w[i]-pcol[i];
      cEdge += hold*hold;
    }
    cEdge /= m;
    cEdge = sqrt(cEdge);
    if(cEdge > lp->epspivot)
      report(lp, SEVERE, "updatePricer: MRS error is %g\n", cEdge);
  }
*/
}
示例#3
0
文件: lp_SOS.c 项目: SimonRit/RTK
STATIC int make_SOSchain(lprec *lp, MYBOOL forceresort)
{
  int      i, j, k, n;
  MYBOOL   *hold = NULL;
  REAL     *order, sum, weight;
  SOSgroup *group = lp->SOS;

  /* PART A: Resort individual SOS member lists, if specified */
  if(forceresort)
    SOS_member_sortlist(group, 0);

  /* PART B: Tally SOS variables and create master SOS variable list */
  n = 0;
  for(i = 0; i < group->sos_count; i++)
    n += group->sos_list[i]->size;
  lp->sos_vars = n;
  if(lp->sos_vars > 0) /* Prevent memory loss in case of multiple solves */
    FREE(lp->sos_priority);
  allocINT(lp, &lp->sos_priority, n, FALSE);
  allocREAL(lp, &order, n, FALSE);

  /* Move variable data to the master SOS list and sort by ascending weight */
  n = 0;
  sum = 0;
  for(i = 0; i < group->sos_count; i++) {
    for(j = 1; j <= group->sos_list[i]->size; j++) {
      lp->sos_priority[n] = group->sos_list[i]->members[j];
      weight = group->sos_list[i]->weights[j];
      sum += weight;
      order[n] = sum;
      n++;
    }
  }
  hpsortex(order, n, 0, sizeof(*order), FALSE, compareREAL, lp->sos_priority);
  FREE(order);

  /* Remove duplicate SOS variables */
  allocMYBOOL(lp, &hold, lp->columns+1, TRUE);
  k = 0;
  for(i = 0; i < n; i++) {
    j = lp->sos_priority[i];
    if(!hold[j]) {
      hold[j] = TRUE;
      if(k < i)
        lp->sos_priority[k] = j;
      k++;
    }
  }
  FREE(hold);

  /* Adjust the size of the master variable list, if necessary */
  if(k < lp->sos_vars) {
    allocINT(lp, &lp->sos_priority, k, AUTOMATIC);
    lp->sos_vars = k;
  }

  return( k );

}
示例#4
0
STATIC MYBOOL resizePricer(lprec *lp)
{
  if(!applyPricer(lp))
    return( TRUE );

  /* Reallocate vector for new size */
  if(!allocREAL(lp, &(lp->edgeVector), lp->sum_alloc+1, AUTOMATIC))
    return( FALSE );

  /* Signal that we have not yet initialized the price vector */
  MEMCLEAR(lp->edgeVector, lp->sum_alloc+1);
  lp->edgeVector[0] = -1;
  return( TRUE );
}
示例#5
0
STATIC REAL auto_scale(lprec *lp)
{
  int    n = 1;
  REAL   scalingmetric = 0, *scalenew = NULL;

  if(lp->scaling_used &&
     ((((lp->scalemode & SCALE_DYNUPDATE) == 0)) || (lp->bb_level > 0)))
    return( scalingmetric);

  if(lp->scalemode != SCALE_NONE) {

    /* Allocate array for incremental scaling if appropriate */
    if((lp->solvecount > 1) && (lp->bb_level < 1) &&
       ((lp->scalemode & SCALE_DYNUPDATE) != 0))
      allocREAL(lp, &scalenew, lp->sum + 1, FALSE);

    if(is_scaletype(lp, SCALE_CURTISREID)) {
      scalingmetric = scaleCR(lp, scalenew);
    }
    else {
      REAL scalinglimit, scalingdelta;
      int  count;

      /* Integer value of scalelimit holds the maximum number of iterations; default to 1 */
      count = (int) floor(lp->scalelimit);
      scalinglimit = lp->scalelimit;
      if((count == 0) || (scalinglimit == 0)) {
        if(scalinglimit > 0)
          count = DEF_SCALINGLIMIT;  /* A non-zero convergence has been given, default to max 5 iterations */
        else
          count = 1;
      }
      else
        scalinglimit -= count;

      /* Scale to desired relative convergence or iteration limit */
      n = 0;
      scalingdelta = 1.0;
      scalingmetric = 1.0;
      while((n < count) && (fabs(scalingdelta) > scalinglimit)) {
        n++;
        scalingdelta = scale(lp, scalenew);
        scalingmetric = scalingmetric*(1+scalingdelta);
      }
      scalingmetric -= 1;
    }
  }

  /* Update the inf norm of the elements of the matrix (excluding the OF) */
  mat_computemax(lp->matA);

  /* Check if we really have to do scaling */
  if(lp->scaling_used && (fabs(scalingmetric) >= lp->epsprimal))
    /* Ok, do it */
    finalize_scaling(lp, scalenew);

  else {

    /* Otherwise reset scaling variables */
    if(lp->scalars != NULL) {
      FREE(lp->scalars);
    }
    lp->scaling_used = FALSE;
    lp->columns_scaled = FALSE;
  }
  if(scalenew != NULL)
    FREE(scalenew);

  return(scalingmetric);
}
示例#6
0
文件: lp_SOS.c 项目: SimonRit/RTK
STATIC int append_SOSrec(SOSrec *SOS, int size, int *variables, REAL *weights)
{
  int   i, oldsize, newsize, nn;
  lprec *lp = SOS->parent->lp;

  oldsize = SOS->size;
  newsize = oldsize + size;
  nn = abs(SOS->type);

 /* Shift existing active data right (normally zero) */
  if(SOS->members == NULL)
    allocINT(lp, &SOS->members, 1+newsize+1+nn, TRUE);
  else {
    allocINT(lp, &SOS->members, 1+newsize+1+nn, AUTOMATIC);
    for(i = newsize+1+nn; i > newsize+1; i--)
    SOS->members[i] = SOS->members[i-size];
  }
  SOS->members[0] = newsize;
  SOS->members[newsize+1] = nn;

 /* Copy the new data into the arrays */
  if(SOS->weights == NULL)
    allocREAL(lp, &SOS->weights, 1+newsize, TRUE);
  else
    allocREAL(lp, &SOS->weights, 1+newsize, AUTOMATIC);
  for(i = oldsize+1; i <= newsize; i++) {
    SOS->members[i] = variables[i-oldsize-1];
    if((SOS->members[i] < 1) || (SOS->members[i] > lp->columns))
      report(lp, IMPORTANT, "append_SOS_rec: Invalid SOS variable definition for index %d\n", SOS->members[i]);
    else {
      if(SOS->isGUB)
        lp->var_type[SOS->members[i]] |= ISGUB;
      else
        lp->var_type[SOS->members[i]] |= ISSOS;
    }
    if(weights == NULL)
      SOS->weights[i] = i;  /* Follow standard, which is sorted ascending */
    else
      SOS->weights[i] = weights[i-oldsize-1];
    SOS->weights[0] += SOS->weights[i];
  }

 /* Sort the new paired lists ascending by weight (simple bubble sort) */
  i = sortByREAL(SOS->members, SOS->weights, newsize, 1, TRUE);
  if(i > 0)
    report(lp, DETAILED, "append_SOS_rec: Non-unique SOS variable weight for index %d\n", i);

 /* Define mapping arrays to search large SOS's faster */
  allocINT(lp, &SOS->membersSorted, newsize, AUTOMATIC);
  allocINT(lp, &SOS->membersMapped, newsize, AUTOMATIC);
  for(i = oldsize+1; i <= newsize; i++) {
    SOS->membersSorted[i - 1] = SOS->members[i];
    SOS->membersMapped[i - 1] = i;
  }
  sortByINT(SOS->membersMapped, SOS->membersSorted, newsize, 0, TRUE);

 /* Confirm the new size */
  SOS->size = newsize;

  return(newsize);

}
示例#7
0
MYBOOL __WINAPI guess_basis(lprec *lp, REAL *guessvector, int *basisvector)
{
  MYBOOL *isnz = NULL, status = FALSE;
  REAL   *values = NULL, *violation = NULL,
         eps = lp->epsprimal,
         *value, error, upB, loB, sortorder = -1.0;
  int    i, j, jj, n, *rownr, *colnr, *slkpos = NULL,
         nrows = lp->rows, ncols = lp->columns, nsum = lp->sum;
  int    *basisnr;
  MATrec *mat = lp->matA;

  if(!mat_validate(mat))
    return( status );

  /* Create helper arrays, providing for multiple use of the violation array */
  if(!allocREAL(lp, &values, nsum+1, TRUE) ||
     !allocREAL(lp, &violation, nsum+1, TRUE))
    goto Finish;

  /* Compute the values of the constraints for the given guess vector */
  i = 0;
  n = get_nonzeros(lp);
  rownr = &COL_MAT_ROWNR(i);
  colnr = &COL_MAT_COLNR(i);
  value = &COL_MAT_VALUE(i);
  for(; i < n; i++, rownr += matRowColStep, colnr += matRowColStep, value += matValueStep)
    values[*rownr] += unscaled_mat(lp, my_chsign(is_chsign(lp, *rownr), *value), *rownr, *colnr) *
                      guessvector[*colnr];
  MEMMOVE(values+nrows+1, guessvector+1, ncols);

  /* Initialize bound "violation" or primal non-degeneracy measures, expressed
     as the absolute value of the differences from the closest bound. */
  for(i = 1; i <= nsum; i++) {
    if(i <= nrows) {
      loB = get_rh_lower(lp, i);
      upB = get_rh_upper(lp, i);
    }
    else {
      loB = get_lowbo(lp, i-nrows);
      upB = get_upbo(lp, i-nrows);
    }

    /* Free constraints/variables */
    if(my_infinite(lp, loB) && my_infinite(lp, upB))
      error = 0;
    /* Violated constraints/variable bounds */
    else if(values[i]+eps < loB)
      error = loB-values[i];
    else if(values[i]-eps > upB)
      error = values[i]-upB;
    /* Non-violated constraints/variables bounds */
    else if(my_infinite(lp, upB))
      error = MAX(0, values[i]-loB);
    else if(my_infinite(lp, loB))
      error = MAX(0, upB-values[i]);
    else
      error = MIN(upB-values[i], values[i]-loB); /* MAX(upB-values[i], values[i]-loB); */
    if(error != 0)
      violation[i] = sortorder*error;
    basisvector[i] = i;
  }

  /* Sort decending , meaning that variables with the largest
     "violations" will be designated basic. Effectively, we are performing a
     greedy type algorithm, but start at the "least interesting" end. */
  sortByREAL(basisvector, violation, nsum, 1, FALSE);
  error = violation[1]; /* Used for setting the return value */

  /* Let us check for obvious row singularities and try to fix these.
     Note that we reuse the memory allocated to the violation array.
     First assemble necessary basis statistics... */
  slkpos = (int *) violation;
  n = nrows+1;
  MEMCLEAR(slkpos, n);
  isnz = (MYBOOL *) (slkpos+n+1);
  MEMCLEAR(isnz, n);
  for(i = 1; i <= nrows; i++) {
    j = abs(basisvector[i]);
    if(j <= nrows) {
      isnz[j] = TRUE;
      slkpos[j] = i;
    }
    else {
      j-= nrows;
      jj = mat->col_end[j-1];
      jj = COL_MAT_ROWNR(jj);
      isnz[jj] = TRUE;
    }
  }
  for(; i <= nsum; i++) {
    j = abs(basisvector[i]);
    if(j <= nrows)
      slkpos[j] = i;
  }

  /* ...then set the corresponding slacks basic for row rank deficient positions */
  for(j = 1; j <= nrows; j++) {
    if(slkpos[j] == 0)
      report(lp, SEVERE, "guess_basis: Internal error");
    if(!isnz[j]) {
      isnz[j] = TRUE;
      i = slkpos[j];
      swapINT(&basisvector[i], &basisvector[j]);
      basisvector[j] = abs(basisvector[j]);
    }
  }

  /* Adjust the non-basic indeces for the (proximal) bound state */
  for(i = nrows+1, basisnr = basisvector+i; i <= nsum; i++, basisnr++) {
    n = *basisnr;
    if(n <= nrows) {
      values[n] -= get_rh_lower(lp, n);
      if(values[n] <= eps)
        *basisnr = -(*basisnr);
    }
    else
      if(values[n]-eps <= get_lowbo(lp, n-nrows))
        *basisnr = -(*basisnr);
  }

/* Lastly normalize all basic variables to be coded as lower-bounded,
   or effectively zero-based in the case of free variables. */
  for(i = 1; i <= nrows; i++)
    basisvector[i] = -abs(basisvector[i]);

  /* Clean up and return status */
  status = (MYBOOL) (error <= eps);
Finish:
  FREE(values);
  FREE(violation);

  return( status );
}
示例#8
0
MYBOOL __WINAPI guess_basis(lprec *lp, REAL *guessvector, int *basisvector)
{
  MYBOOL *isnz, status = FALSE;
  REAL   *values = NULL, *violation = NULL,
         eps = lp->epsprimal,
         *value, error, upB, loB, sortorder = 1.0;
  int    i, j, jj, n, *rownr, *colnr, *slkpos,
         nrows = lp->rows, ncols = lp->columns;
  MATrec *mat = lp->matA;

  if(!mat_validate(mat))
    return( status );

  /* Create helper arrays */
  if(!allocREAL(lp, &values, lp->sum+1, TRUE) ||
     !allocREAL(lp, &violation, lp->sum+1, TRUE))
    goto Finish;

  /* Compute values of slack variables for given guess vector */
  i = 0;
  n = get_nonzeros(lp);
  rownr = &COL_MAT_ROWNR(i);
  colnr = &COL_MAT_COLNR(i);
  value = &COL_MAT_VALUE(i);
  for(; i < n; i++, rownr += matRowColStep, colnr += matRowColStep, value += matValueStep)
    values[*rownr] += unscaled_mat(lp, my_chsign(is_chsign(lp, *rownr), *value), *rownr, *colnr) *
                      guessvector[*colnr];
  MEMMOVE(values+nrows+1, guessvector+1, ncols);

  /* Initialize constraint bound violation measures (expressed as positive values) */
  for(i = 1; i <= nrows; i++) {
    upB = get_rh_upper(lp, i);
    loB = get_rh_lower(lp, i);
    error = values[i] - upB;
    if(error > -eps)
      violation[i] = sortorder*MAX(0,error);
    else {
      error = loB - values[i];
      if(error > -eps)
        violation[i] = sortorder*MAX(0,error);
      else if(my_infinite(lp, loB) && my_infinite(lp, upB))
        ;
      else if(my_infinite(lp, upB))
        violation[i] = sortorder*(loB - values[i]);
      else if(my_infinite(lp, loB))
        violation[i] = sortorder*(values[i] - upB);
      else
        violation[i] = -sortorder*MAX(upB - values[i], values[i] - loB);
    }
    basisvector[i] = i;
  }

  /* Initialize user variable bound violation measures (expressed as positive values) */
  for(i = 1; i <= ncols; i++) {
    n = nrows+i;
    upB = get_upbo(lp, i);
    loB = get_lowbo(lp, i);
    error = guessvector[i] - upB;
    if(error > -eps)
      violation[n] = sortorder*MAX(0,error);
    else {
      error = loB - values[n];
      if(error > -eps)
        violation[n] = sortorder*MAX(0,error);
      else if(my_infinite(lp, loB) && my_infinite(lp, upB))
        ;
      else if(my_infinite(lp, upB))
        violation[n] = sortorder*(loB - values[n]);
      else if(my_infinite(lp, loB))
        violation[n] = sortorder*(values[n] - upB);
      else
        violation[n] = -sortorder*MAX(upB - values[n], values[n] - loB);
    }
    basisvector[n] = n;
  }

  /* Sort decending by violation; this means that variables with
     the largest violations will be designated as basic */
  sortByREAL(basisvector, violation, lp->sum, 1, FALSE);
  error = violation[1];

  /* Adjust the non-basic indeces for the (proximal) bound state */
  for(i = nrows+1, rownr = basisvector+i; i <= lp->sum; i++, rownr++) {
    if(*rownr <= nrows) {
      values[*rownr] -= lp->orig_rhs[*rownr];
      if(values[*rownr] <= eps)
        *rownr = -(*rownr);
    }
    else
      if(values[i] <= get_lowbo(lp, (*rownr)-nrows)+eps)
        *rownr = -(*rownr);
  }

  /* Let us check for obvious row singularities and try to fix these;
     First assemble necessary basis statistics... */
  isnz = (MYBOOL *) values;
  MEMCLEAR(isnz, nrows+1);
  slkpos = (int *) violation;
  MEMCLEAR(slkpos, nrows+1);
  for(i = 1; i <= nrows; i++) {
    j = abs(basisvector[i]);
    if(j <= nrows) {
      isnz[j] = TRUE;
      slkpos[j] = i;
    }
    else {
      j-= nrows;
      jj = mat->col_end[j-1];
      isnz[COL_MAT_ROWNR(jj)] = TRUE;
/*      if(++jj < mat->col_end[j])
        isnz[COL_MAT_ROWNR(jj)] = TRUE; */
    }
  }
  for(; i <= lp->sum; i++) {
    j = abs(basisvector[i]);
    if(j <= nrows)
      slkpos[j] = i;
  }

  /* ...then set the corresponding slacks basic for row rank deficient positions */
  for(j = 1; j <= nrows; j++) {
#ifdef Paranoia
    if(slkpos[j] == 0)
      report(lp, SEVERE, "guess_basis: Internal error");
#endif
    if(!isnz[j]) {
      isnz[j] = TRUE;
      i = slkpos[j];
      swapINT(&basisvector[i], &basisvector[j]);
      basisvector[j] = abs(basisvector[j]);
    }
  }

  /* Lastly normalize all basic variables to be coded as lower-bounded */
  for(i = 1; i <= nrows; i++)
    basisvector[i] = -abs(basisvector[i]);

  /* Clean up and return status */
  status = (MYBOOL) (error <= eps);
Finish:
  FREE(values);
  FREE(violation);

  return( status );
}
示例#9
0
MYBOOL __WINAPI guess_basis(lprec *lp, REAL *guessvector, int *basisvector)
{
  MYBOOL status = FALSE;
  REAL   *values = NULL, *violation = NULL,
         *value, error, upB, loB, sortorder = 1.0;
  int    i, n, *rownr, *colnr;
  MATrec *mat = lp->matA;

  if(!mat_validate(lp->matA))
    return( status );

  /* Create helper arrays */
  if(!allocREAL(lp, &values, lp->sum+1, TRUE) ||
     !allocREAL(lp, &violation, lp->sum+1, TRUE))
    goto Finish;

  /* Compute values of slack variables for given guess vector */
  i = 0;
  n = get_nonzeros(lp);
  rownr = &COL_MAT_ROWNR(i);
  colnr = &COL_MAT_COLNR(i);
  value = &COL_MAT_VALUE(i);
  for(; i < n; i++, rownr += matRowColStep, colnr += matRowColStep, value += matValueStep)
    values[*rownr] += unscaled_mat(lp, my_chsign(is_chsign(lp, *rownr), *value), *rownr, *colnr) *
                      guessvector[*colnr];
  MEMMOVE(values+lp->rows+1, guessvector+1, lp->columns);

  /* Initialize constraint bound violation measures */
  for(i = 1; i <= lp->rows; i++) {
    upB = get_rh_upper(lp, i);
    loB = get_rh_lower(lp, i);
    error = values[i] - upB;
    if(error > lp->epsprimal)
      violation[i] = sortorder*error;
    else {
      error = loB - values[i];
      if(error > lp->epsprimal)
        violation[i] = sortorder*error;
      else if(is_infinite(lp, loB) && is_infinite(lp, upB))
        ;
      else if(is_infinite(lp, upB))
        violation[i] = sortorder*(loB - values[i]);
      else if(is_infinite(lp, loB))
        violation[i] = sortorder*(values[i] - upB);
      else
        violation[i] = - sortorder*MAX(upB - values[i], values[i] - loB);
    }
    basisvector[i] = i;
  }

  /* Initialize user variable bound violation measures */
  for(i = 1; i <= lp->columns; i++) {
    n = lp->rows+i;
    upB = get_upbo(lp, i);
    loB = get_lowbo(lp, i);
    error = guessvector[i] - upB;
    if(error > lp->epsprimal)
      violation[n] = sortorder*error;
    else {
      error = loB - values[n];
      if(error > lp->epsprimal)
        violation[n] = sortorder*error;
      else if(is_infinite(lp, loB) && is_infinite(lp, upB))
        ;
      else if(is_infinite(lp, upB))
        violation[n] = sortorder*(loB - values[n]);
      else if(is_infinite(lp, loB))
        violation[n] = sortorder*(values[n] - upB);
      else
        violation[n] = - sortorder*MAX(upB - values[n], values[n] - loB);
    }
    basisvector[n] = n;
  }

  /* Sort decending by violation; this means that variables with
     the largest violations will be designated as basic */
  sortByREAL(basisvector, violation, lp->sum, 1, FALSE);

  /* Adjust the non-basic indeces for the (proximal) bound state */
  error = lp->epsprimal;
  for(i = lp->rows+1, rownr = basisvector+i; i <= lp->sum; i++, rownr++) {
    if(*rownr <= lp->rows) {
      if(values[*rownr] <= get_rh_lower(lp, *rownr)+error)
        *rownr = -(*rownr);
    }
    else
      if(values[i] <= get_lowbo(lp, (*rownr)-lp->rows)+error)
        *rownr = -(*rownr);
  }

  /* Clean up and return status */
  status = (MYBOOL) (violation[1] == 0);
Finish:
  FREE(values);
  FREE(violation);


  return( status );
}
示例#10
0
MYBOOL crash_basis(lprec *lp)
{
  int     i;
  MATrec  *mat = lp->matA;
  MYBOOL  ok = TRUE;

  /* Initialize basis indicators */
  if(lp->basis_valid)
    lp->var_basic[0] = FALSE;
  else
    default_basis(lp);

  /* Set initial partial pricing blocks */
  if(lp->rowblocks != NULL)
    lp->rowblocks->blocknow = 1;
  if(lp->colblocks != NULL)
    lp->colblocks->blocknow = ((lp->crashmode == CRASH_NONE) || (lp->colblocks->blockcount == 1) ? 1 : 2);

  /* Construct a basis that is in some measure the "most feasible" */
  if((lp->crashmode == CRASH_MOSTFEASIBLE) && mat_validate(mat)) {
    /* The logic here follows Maros */
    LLrec   *rowLL = NULL, *colLL = NULL;
    int     ii, rx, cx, ix, nz;
    REAL    wx, tx, *rowMAX = NULL, *colMAX = NULL;
    int     *rowNZ = NULL, *colNZ = NULL, *rowWT = NULL, *colWT = NULL;
    REAL    *value;
    int     *rownr, *colnr;

    report(lp, NORMAL, "crash_basis: 'Most feasible' basis crashing selected\n");

    /* Tally row and column non-zero counts */
    ok = allocINT(lp,  &rowNZ, lp->rows+1,     TRUE) &&
         allocINT(lp,  &colNZ, lp->columns+1,  TRUE) &&
         allocREAL(lp, &rowMAX, lp->rows+1,    FALSE) &&
         allocREAL(lp, &colMAX, lp->columns+1, FALSE);
    if(!ok)
      goto Finish;

    nz = mat_nonzeros(mat);
    rownr = &COL_MAT_ROWNR(0);
    colnr = &COL_MAT_COLNR(0);
    value = &COL_MAT_VALUE(0);
    for(i = 0; i < nz;
        i++, rownr += matRowColStep, colnr += matRowColStep, value += matValueStep) {
      rx = *rownr;
      cx = *colnr;
      wx = fabs(*value);
      rowNZ[rx]++;
      colNZ[cx]++;
      if(i == 0) {
        rowMAX[rx] = wx;
        colMAX[cx] = wx;
        colMAX[0]  = wx;
      }
      else {
        SETMAX(rowMAX[rx], wx);
        SETMAX(colMAX[cx], wx);
        SETMAX(colMAX[0],  wx);
      }
    }
    /* Reduce counts for small magnitude to preserve stability */
    rownr = &COL_MAT_ROWNR(0);
    colnr = &COL_MAT_COLNR(0);
    value = &COL_MAT_VALUE(0);
    for(i = 0; i < nz;
        i++, rownr += matRowColStep, colnr += matRowColStep, value += matValueStep) {
      rx = *rownr;
      cx = *colnr;
      wx = fabs(*value);
#ifdef CRASH_SIMPLESCALE
      if(wx < CRASH_THRESHOLD * colMAX[0]) {
        rowNZ[rx]--;
        colNZ[cx]--;
      }
#else
      if(wx < CRASH_THRESHOLD * rowMAX[rx])
        rowNZ[rx]--;
      if(wx < CRASH_THRESHOLD * colMAX[cx])
        colNZ[cx]--;
#endif
    }

    /* Set up priority tables */
    ok = allocINT(lp, &rowWT, lp->rows+1, TRUE);
    createLink(lp->rows,    &rowLL, NULL);
    ok &= (rowLL != NULL);
    if(!ok)
      goto Finish;
    for(i = 1; i <= lp->rows; i++) {
      if(get_constr_type(lp, i)==EQ)
        ii = 3;
      else if(lp->upbo[i] < lp->infinite)
        ii = 2;
      else if(fabs(lp->rhs[i]) < lp->infinite)
        ii = 1;
      else
        ii = 0;
      rowWT[i] = ii;
      if(ii > 0)
        appendLink(rowLL, i);
    }
    ok = allocINT(lp, &colWT, lp->columns+1, TRUE);
    createLink(lp->columns, &colLL, NULL);
    ok &= (colLL != NULL);
    if(!ok)
      goto Finish;
    for(i = 1; i <= lp->columns; i++) {
      ix = lp->rows+i;
      if(is_unbounded(lp, i))
        ii = 3;
      else if(lp->upbo[ix] >= lp->infinite)
        ii = 2;
      else if(fabs(lp->upbo[ix]-lp->lowbo[ix]) > lp->epsmachine)
        ii = 1;
      else
        ii = 0;
      colWT[i] = ii;
      if(ii > 0)
        appendLink(colLL, i);
    }

    /* Loop over all basis variables */
    for(i = 1; i <= lp->rows; i++) {

      /* Select row */
      rx = 0;
      wx = -lp->infinite;
      for(ii = firstActiveLink(rowLL); ii > 0; ii = nextActiveLink(rowLL, ii)) {
        tx = rowWT[ii] - CRASH_SPACER*rowNZ[ii];
        if(tx > wx) {
          rx = ii;
          wx = tx;
        }
      }
      if(rx == 0)
        break;
      removeLink(rowLL, rx);

      /* Select column */
      cx = 0;
      wx = -lp->infinite;
      for(ii = mat->row_end[rx-1]; ii < mat->row_end[rx]; ii++) {

        /* Update NZ column counts for row selected above */
        tx = fabs(ROW_MAT_VALUE(ii));
        ix = ROW_MAT_COLNR(ii);
#ifdef CRASH_SIMPLESCALE
        if(tx >= CRASH_THRESHOLD * colMAX[0])
#else
        if(tx >= CRASH_THRESHOLD * colMAX[ix])
#endif
          colNZ[ix]--;
        if(!isActiveLink(colLL, ix) || (tx < CRASH_THRESHOLD * rowMAX[rx]))
          continue;

        /* Now do the test for best pivot */
        tx = my_sign(lp->orig_obj[ix]) - my_sign(ROW_MAT_VALUE(ii));
        tx = colWT[ix] + CRASH_WEIGHT*tx - CRASH_SPACER*colNZ[ix];
        if(tx > wx) {
          cx = ix;
          wx = tx;
        }
      }
      if(cx == 0)
        break;
      removeLink(colLL, cx);

      /* Update row NZ counts */
      ii = mat->col_end[cx-1];
      rownr = &COL_MAT_ROWNR(ii);
      value = &COL_MAT_VALUE(ii);
      for(; ii < mat->col_end[cx];
          ii++, rownr += matRowColStep, value += matValueStep) {
        wx = fabs(*value);
        ix = *rownr;
#ifdef CRASH_SIMPLESCALE
        if(wx >= CRASH_THRESHOLD * colMAX[0])
#else
        if(wx >= CRASH_THRESHOLD * rowMAX[ix])
#endif
          rowNZ[ix]--;
      }

      /* Set new basis variable */
      set_basisvar(lp, rx, lp->rows+cx);
    }

    /* Clean up */
Finish:
    FREE(rowNZ);
    FREE(colNZ);
    FREE(rowMAX);
    FREE(colMAX);
    FREE(rowWT);
    FREE(colWT);
    freeLink(&rowLL);
    freeLink(&colLL);
  }

  /* Construct a basis that is in some measure the "least degenerate" */
  else if((lp->crashmode == CRASH_LEASTDEGENERATE) && mat_validate(mat)) {
    /* The logic here follows Maros */
    LLrec   *rowLL = NULL, *colLL = NULL;
    int     ii, rx, cx, ix, nz, *merit = NULL;
    REAL    *value, wx, hold, *rhs = NULL, *eta = NULL;
    int     *rownr, *colnr;

    report(lp, NORMAL, "crash_basis: 'Least degenerate' basis crashing selected\n");

    /* Create temporary arrays */
    ok = allocINT(lp,  &merit, lp->columns + 1, FALSE) &&
         allocREAL(lp, &eta, lp->rows + 1, FALSE) &&
         allocREAL(lp, &rhs, lp->rows + 1, FALSE);
    createLink(lp->columns, &colLL, NULL);
    createLink(lp->rows, &rowLL, NULL);
    ok &= (colLL != NULL) && (rowLL != NULL);
    if(!ok)
      goto FinishLD;
    MEMCOPY(rhs, lp->orig_rhs, lp->rows + 1);
    for(i = 1; i <= lp->columns; i++)
      appendLink(colLL, i);
    for(i = 1; i <= lp->rows; i++)
      appendLink(rowLL, i);

    /* Loop until we have found enough new bases */
    while(colLL->count > 0) {

      /* Tally non-zeros matching in RHS and each active column */
      nz = mat_nonzeros(mat);
      rownr = &COL_MAT_ROWNR(0);
      colnr = &COL_MAT_COLNR(0);
      ii = 0;
      MEMCLEAR(merit, lp->columns + 1);
      for(i = 0; i < nz;
          i++, rownr += matRowColStep, colnr += matRowColStep) {
        rx = *rownr;
        cx = *colnr;
        if(isActiveLink(colLL, cx) && (rhs[rx] != 0)) {
          merit[cx]++;
          ii++;
        }
      }
      if(ii == 0)
        break;

      /* Find maximal match; break ties with column length */
      i = firstActiveLink(colLL);
      cx = i;
      for(i = nextActiveLink(colLL, i); i != 0; i = nextActiveLink(colLL, i)) {
        if(merit[i] >= merit[cx]) {
          if((merit[i] > merit[cx]) || (mat_collength(mat, i) > mat_collength(mat, cx)))
            cx = i;
        }
      }

      /* Determine the best pivot row */
      i = mat->col_end[cx-1];
      nz = mat->col_end[cx];
      rownr = &COL_MAT_ROWNR(i);
      value = &COL_MAT_VALUE(i);
      rx = 0;
      wx = 0;
      MEMCLEAR(eta, lp->rows + 1);
      for(; i < nz;
          i++, rownr += matRowColStep, value += matValueStep) {
        ix = *rownr;
        hold = *value;
        eta[ix] = rhs[ix] / hold;
        hold = fabs(hold);
        if(isActiveLink(rowLL, ix) && (hold > wx)) {
          wx = hold;
          rx = ix;
        }
      }

      /* Set new basis variable */
      if(rx > 0) {

        /* We have to update the rhs vector for the implied transformation
          in order to be able to find the new RHS non-zero pattern */
        for(i = 1; i <= lp->rows; i++)
           rhs[i] -= wx * eta[i];
        rhs[rx] = wx;

        /* Do the exchange */
        set_basisvar(lp, rx, lp->rows+cx);
        removeLink(rowLL, rx);
      }
      removeLink(colLL, cx);

    }

    /* Clean up */
FinishLD:
    FREE(merit);
    FREE(rhs);
    freeLink(&rowLL);
    freeLink(&colLL);

  }
  return( ok );
}
示例#11
0
STATIC void updatePricer(lprec *lp, int rownr, int colnr, REAL *pcol, REAL *prow, int *nzprow)
{
  REAL   *vEdge = NULL, cEdge, hold, *newEdge, *w = NULL;
  int    i, m, n, exitcol, errlevel = DETAILED;
  MYBOOL forceRefresh = FALSE, isDual, isDEVEX;

  if(!applyPricer(lp))
    return;

  /* Make sure we have something to update */
  hold = lp->edgeVector[0];
  if(hold < 0)
    return;
  isDual = (MYBOOL) (hold > 0);

  /* Do common initializations and computations */
  m = lp->rows;
  n = lp->sum;
  isDEVEX = is_piv_rule(lp, PRICER_DEVEX);
  exitcol = lp->var_basic[rownr];

  /* Solve/copy Bw = a */
/*  formWeights(lp, colnr, NULL, &w);  Experimental */
  formWeights(lp, colnr, pcol, &w);

  /* Price norms for the dual simplex - the basic columns */
  if(isDual) {
    REAL rw;
    int  targetcol;

    /* Don't need to compute cross-products with DEVEX */
    if(!isDEVEX) {
      allocREAL(lp, &vEdge, m+1, FALSE);

    /* Extract the row of the inverse containing the leaving variable
       and then form the dot products against the other variables, i.e. "Tau" */
#if 0 /* Extract row explicitly */
      bsolve(lp, rownr, vEdge, 0, 0.0);
#else /* Reuse previously extracted row data */
      MEMCOPY(vEdge, prow, m+1);
      vEdge[0] = 0;
#endif
      lp->bfp_ftran_normal(lp, vEdge, NULL);
    }

   /* Deal with the variable entering the basis to become a new leaving candidate */
    cEdge = lp->edgeVector[exitcol];
    rw = w[rownr];
    hold = 1 / rw;
    lp->edgeVector[colnr] = (hold*hold) * cEdge;

   /* Possibly adjust initial value in case of Devex */
    if(isDEVEX && !DEVEX_ENHANCED && (lp->edgeVector[colnr] < DEVEX_MINVALUE))
      lp->edgeVector[colnr] = DEVEX_MINVALUE;

#ifdef Paranoia
    if(lp->edgeVector[colnr] <= lp->epsmachine)
      report(lp, errlevel, "updatePricer: Invalid dual norm %g at entering index %d - iteration %d\n",
                           lp->edgeVector[colnr], rownr, lp->total_iter+lp->current_iter);
#endif

   /* Then loop over all basic variables, but skip the leaving row */
    for(i = 1; i <= m; i++) {
      if(i == rownr)
        continue;
      targetcol = lp->var_basic[i];
      hold = w[i];
      if(hold == 0)
        continue;
      hold /= rw;
      if(fabs(hold) < lp->epsmachine)
        continue;

      newEdge = &(lp->edgeVector[targetcol]);
      *newEdge += (hold*hold) * cEdge;
      if(isDEVEX) {
        if((*newEdge) > DEVEX_RESTARTLIMIT) {
          forceRefresh = TRUE;
          break;
        }
      }
      else {
        *newEdge -= 2*hold*vEdge[i];
#ifdef xxApplySteepestEdgeMinimum
        *newEdge = my_max(*newEdge, hold*hold+1); /* Kludge; use the primal lower bound */
#else
        if(*newEdge <= 0) {
          report(lp, errlevel, "updatePricer: Invalid dual norm %g at index %d - iteration %d\n",
                                *newEdge, i, lp->total_iter+lp->current_iter);
          forceRefresh = TRUE;
          break;
        }
#endif
      }
    }


  }
  /* Price norms for the primal simplex - the non-basic columns */
  else {

    REAL *vTemp, *vAlpha, cAlpha;
    int  *coltarget;

    allocREAL(lp, &vTemp, m+1, TRUE);
    allocREAL(lp, &vAlpha, n+1, TRUE);

    /* Check if we have strategy fallback for the primal */
    if(!isDEVEX)
      isDEVEX = is_piv_mode(lp, PRICE_PRIMALFALLBACK);

    /* Initialize column target array */
    coltarget = (int *) mempool_obtainVector(lp->workarrays, lp->sum+1, sizeof(*coltarget));
    if(!get_colIndexA(lp, SCAN_ALLVARS+USE_NONBASICVARS, coltarget, FALSE)) {
      mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE);
      return;
    }

    /* Don't need to compute cross-products with DEVEX */
    if(!isDEVEX) {
      vEdge = (REAL *) calloc((n + 1), sizeof(*vEdge));

      /* Compute v and then N'v */
      MEMCOPY(vTemp, w, m+1);
      bsolve(lp, -1, vTemp, NULL, lp->epsmachine*DOUBLEROUND, 0.0);
      vTemp[0] = 0;
      prod_xA(lp, coltarget, vTemp, NULL, XRESULT_FREE, lp->epsmachine, 0.0,
                             vEdge, NULL);
    }

    /* Compute Sigma and then Alpha */
    bsolve(lp, rownr, vTemp, NULL, 0*DOUBLEROUND, 0.0);
    vTemp[0] = 0;
    prod_xA(lp, coltarget, vTemp, NULL, XRESULT_FREE, lp->epsmachine, 0.0,
                           vAlpha, NULL);
    mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE);

    /* Update the squared steepest edge norms; first store some constants */
    cEdge = lp->edgeVector[colnr];
    cAlpha = vAlpha[colnr];

    /* Deal with the variable leaving the basis to become a new entry candidate */
    hold = 1 / cAlpha;
    lp->edgeVector[exitcol] = (hold*hold) * cEdge;

   /* Possibly adjust initial value in case of Devex */
    if(isDEVEX && !DEVEX_ENHANCED && (lp->edgeVector[exitcol] < DEVEX_MINVALUE))
      lp->edgeVector[exitcol] = DEVEX_MINVALUE;

#ifdef Paranoia
    if(lp->edgeVector[exitcol] <= lp->epsmachine)
      report(lp, errlevel, "updatePricer: Invalid primal norm %g at leaving index %d - iteration %d\n",
                          lp->edgeVector[exitcol], exitcol, lp->total_iter+lp->current_iter);
#endif

    /* Then loop over all non-basic variables, but skip the entering column */
    for(i = 1; i <= lp->sum; i++) {
      if(lp->is_basic[i] || (i == colnr))
        continue;
      hold = vAlpha[i];
      if(hold == 0)
        continue;
      hold /= cAlpha;
      if(fabs(hold) < lp->epsmachine)
        continue;

      newEdge = &(lp->edgeVector[i]);
      *newEdge += (hold*hold) * cEdge;
      if(isDEVEX) {
        if((*newEdge) > DEVEX_RESTARTLIMIT) {
          forceRefresh = TRUE;
          break;
        }
      }
      else {
        *newEdge -= 2*hold*vEdge[i];
#ifdef ApplySteepestEdgeMinimum
        *newEdge = my_max(*newEdge, hold*hold+1);
#else
        if(*newEdge < 0) {
          report(lp, errlevel, "updatePricer: Invalid primal norm %g at index %d - iteration %d\n",
                               *newEdge, i, lp->total_iter+lp->current_iter);
          if(lp->spx_trace)
            report(lp, errlevel, "Error detail: (RelAlpha=%g, vEdge=%g, cEdge=%g)\n", hold, vEdge[i], cEdge);
          forceRefresh = TRUE;
          break;
        }
#endif
      }
    }

    FREE(vAlpha);
    FREE(vTemp);

  }

  if(vEdge != NULL)
    FREE(vEdge);
  freeWeights(w);

  if(forceRefresh)
    restartPricer(lp, AUTOMATIC);

}
示例#12
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 {
示例#13
0
/* Report the traditional tableau corresponding to the current basis */
MYBOOL REPORT_tableau(lprec *lp)
{
  int  j, row_nr, *coltarget;
  LPSREAL *prow = NULL;
  FILE *stream = lp->outstream;

  if(lp->outstream == NULL)
    return(FALSE);

  if(!lp->model_is_valid || !has_BFP(lp) ||
     (get_total_iter(lp) == 0) || (lp->spx_status == NOTRUN)) {
    lp->spx_status = NOTRUN;
    return(FALSE);
  }
  if(!allocREAL(lp, &prow,lp->sum + 1, TRUE)) {
    lp->spx_status = NOMEMORY;
    return(FALSE);
  }

  fprintf(stream, "\n");
  fprintf(stream, "Tableau at iter %.0f:\n", (double) get_total_iter(lp));

  for(j = 1; j <= lp->sum; j++)
    if (!lp->is_basic[j])
      fprintf(stream, "%15d", (j <= lp->rows ?
                               (j + lp->columns) * ((lp->orig_upbo[j] == 0) ||
                                                    (is_chsign(lp, j)) ? 1 : -1) : j - lp->rows) *
                              (lp->is_lower[j] ? 1 : -1));
  fprintf(stream, "\n");

  coltarget = (int *) mempool_obtainVector(lp->workarrays, lp->columns+1, sizeof(*coltarget));
  if(!get_colIndexA(lp, SCAN_USERVARS+USE_NONBASICVARS, coltarget, FALSE)) {
    mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE);
    return(FALSE);
  }
  for(row_nr = 1; (row_nr <= lp->rows + 1); row_nr++) {
    if (row_nr <= lp->rows)
      fprintf(stream, "%3d", (lp->var_basic[row_nr] <= lp->rows ?
                              (lp->var_basic[row_nr] + lp->columns) * ((lp->orig_upbo[lp->var_basic [row_nr]] == 0) ||
                                                                       (is_chsign(lp, lp->var_basic[row_nr])) ? 1 : -1) : lp->var_basic[row_nr] - lp->rows) *
                             (lp->is_lower[lp->var_basic [row_nr]] ? 1 : -1));
    else
      fprintf(stream, "   ");
    bsolve(lp, row_nr <= lp->rows ? row_nr : 0, prow, NULL, lp->epsmachine*DOUBLEROUND, 1.0);
    prod_xA(lp, coltarget, prow, NULL, lp->epsmachine, 1.0,
                                       prow, NULL, MAT_ROUNDDEFAULT);

    for(j = 1; j <= lp->rows + lp->columns; j++)
      if (!lp->is_basic[j])
        fprintf(stream, "%15.7f", prow[j] * (lp->is_lower[j] ? 1 : -1) *
                                            (row_nr <= lp->rows ? 1 : -1));
    fprintf(stream, "%15.7f", lp->rhs[row_nr <= lp->rows ? row_nr : 0] *
                              (double) ((row_nr <= lp->rows) || (is_maxim(lp)) ? 1 : -1));
    fprintf(stream, "\n");
  }
  fflush(stream);

  mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE);
  FREE(prow);
  return(TRUE);
}
示例#14
0
STATIC REAL scale(lprec *lp, REAL *scaledelta)
{
  int     i, j, nz, row_count, nzOF = 0;
  REAL    *row_max, *row_min, *scalechange = NULL, absval;
  REAL    col_max, col_min;
  MYBOOL  rowscaled, colscaled;
  MATrec  *mat = lp->matA;
  REAL    *value;
  int     *rownr;

  if(is_scaletype(lp, SCALE_NONE))
    return(0.0);

  if(!lp->scaling_used) {
    allocREAL(lp, &lp->scalars, lp->sum_alloc + 1, FALSE);
    for(i = 0; i <= lp->sum; i++) {
      lp->scalars[i] = 1;
    }
    lp->scaling_used = TRUE;
  }
#ifdef Paranoia
  else
    for(i = 0; i <= lp->sum; i++) {
      if(lp->scalars[i] == 0)
        report(lp, SEVERE, "scale: Zero-valued scalar found at index %d\n", i);
    }
#endif
  if(scaledelta == NULL)
    allocREAL(lp, &scalechange, lp->sum + 1, FALSE);
  else
    scalechange = scaledelta;

 /* Must initialize due to computation of scaling statistic - KE */
  for(i = 0; i <= lp->sum; i++)
    scalechange[i] = 1;

  row_count = lp->rows;
  allocREAL(lp, &row_max, row_count + 1, TRUE);
  allocREAL(lp, &row_min, row_count + 1, FALSE);

  /* Initialise min and max values of rows */
  for(i = 0; i <= row_count; i++) {
    if(is_scaletype(lp, SCALE_MEAN))
      row_min[i] = 0;             /* Carries the count of elements */
    else
      row_min[i] = lp->infinite;  /* Carries the minimum element */
  }

  /* Calculate row scaling data */
  for(j = 1; j <= lp->columns; j++) {

    absval = lp->orig_obj[j];
    if(absval != 0) {
      absval = scaled_mat(lp, absval, 0, j);
      accumulate_for_scale(lp, &row_min[0], &row_max[0], absval);
      nzOF++;
    }

    i = mat->col_end[j - 1];
    value = &(COL_MAT_VALUE(i));
    rownr = &(COL_MAT_ROWNR(i));
    nz = mat->col_end[j];
    for(; i < nz;
        i++, value += matValueStep, rownr += matRowColStep) {
      absval = scaled_mat(lp, *value, *rownr, j);
      accumulate_for_scale(lp, &row_min[*rownr], &row_max[*rownr], absval);
    }
  }

  /* Calculate scale factors for rows */
  i = 0;
  for(; i <= lp->rows; i++) {
    if(i == 0)
      nz = nzOF;
    else
      nz = mat_rowlength(lp->matA, i);
    absval = minmax_to_scale(lp, row_min[i], row_max[i], nz); /* nz instead of nzOF KJEI 20/05/2010 */
    if(absval == 0)
      absval = 1;
    scalechange[i] = absval;
  }

  FREE(row_max);
  FREE(row_min);

  /* Row-scale the matrix (including the objective function and Lagrangean constraints) */
  rowscaled = scale_updaterows(lp, scalechange, TRUE);

  /* Calculate column scales */
  i = 1;
  for(j = 1; j <= lp->columns; j++) {
    if(is_int(lp,j) && !is_integerscaling(lp)) { /* do not scale integer columns */
      scalechange[lp->rows + j] = 1;
    }
    else {
      col_max = 0;
      if(is_scaletype(lp, SCALE_MEAN))
        col_min = 0;
      else
        col_min = lp->infinite;

      absval = lp->orig_obj[j];
      if(absval != 0) {
        absval = scaled_mat(lp, absval, 0, j);
        accumulate_for_scale(lp, &col_min, &col_max, absval);
      }

      i = mat->col_end[j - 1];
      value = &(COL_MAT_VALUE(i));
      rownr = &(COL_MAT_ROWNR(i));
      nz = mat->col_end[j];
      for(; i < nz;
          i++, value += matValueStep, rownr += matRowColStep) {
        absval = scaled_mat(lp, *value, *rownr, j);
        accumulate_for_scale(lp, &col_min, &col_max, absval);
      }
      nz = mat_collength(lp->matA, j);
      if(fabs(lp->orig_obj[j]) > 0)
        nz++;
      scalechange[lp->rows + j] = minmax_to_scale(lp, col_min, col_max, nz);
    }
  }

  /* ... and then column-scale the already row-scaled matrix */
  colscaled = scale_updatecolumns(lp, &scalechange[lp->rows], TRUE);

  /* Create a geometric mean-type measure of the extent of scaling performed; */
  /* ideally, upon successive calls to scale() the value should converge to 0 */
  if(rowscaled || colscaled) {
    col_max = 0;
    for(j = 1; j <= lp->columns; j++)
      col_max += log(scalechange[lp->rows + j]);
    col_max = exp(col_max/lp->columns);

    i = 0;
    col_min = 0;
    for(; i <= lp->rows; i++)
      col_min += log(scalechange[i]);
    col_min = exp(col_min/row_count);
  }
  else {
    col_max = 1;
    col_min = 1;
  }

  if(scaledelta == NULL)
    FREE(scalechange);

  return(1 - sqrt(col_max*col_min));
}
示例#15
0
/* MUST MODIFY */
MYBOOL BFP_CALLMODEL bfp_resize(lprec *lp, int newsize)
{
  INVrec *lu;

  lu = lp->invB;

  /* Increment dimensionality since we put the objective row at the top */
  newsize = newsize + bfp_rowoffset(lp);
  lu->dimalloc = newsize;

  /* Allocate index tracker arrays, LU matrices and various work vectors */
  if(!allocREAL(lp, &(lu->value), newsize+MATINDEXBASE, AUTOMATIC))
    return( FALSE );

  /* Data specific to the factorization engine */
  if(lu->LUSOL != NULL) {
    if(newsize > 0 || 1)
      LUSOL_sizeto(lu->LUSOL, newsize, newsize, 0);
    else {
      LUSOL_free(lu->LUSOL);
      lu->LUSOL = NULL;
    }
  }
  else if(newsize > 0 || 1) {
    int  asize;
    REAL bsize;

    lu->LUSOL = LUSOL_create(NULL, 0, LUSOL_PIVMOD_TPP, bfp_pivotmax(lp)*0);

#if 1
    lu->LUSOL->luparm[LUSOL_IP_ACCELERATION]  = LUSOL_AUTOORDER;
    lu->LUSOL->parmlu[LUSOL_RP_SMARTRATIO]    = 0.50;
#endif
#if 0
    lu->timed_refact = DEF_TIMEDREFACT;
#else
    lu->timed_refact = FALSE;
#endif

    /* The following adjustments seem necessary to make the really tough NETLIB
       models perform reliably and still performant (e.g. cycle.mps) */
#if 0
    lu->LUSOL->parmlu[LUSOL_RP_SMALLDIAG_U]   =
    lu->LUSOL->parmlu[LUSOL_RP_EPSDIAG_U]     = lp->epsprimal;
#endif
#if 0
    lu->LUSOL->parmlu[LUSOL_RP_ZEROTOLERANCE] = lp->epsvalue;
#endif

#if 1
    LUSOL_setpivotmodel(lu->LUSOL, LUSOL_PIVMOD_NOCHANGE, LUSOL_PIVTOL_SLIM);
#else
    LUSOL_setpivotmodel(lu->LUSOL, LUSOL_PIVMOD_NOCHANGE, LUSOL_PIVTOL_TIGHT);
#endif

#ifdef LUSOL_UseBLAS
/*    if(fileSearchPath("PATH", "myBLAS.DLL", NULL) && load_BLAS("myBLAS")) */
    if(is_nativeBLAS() && load_BLAS(libnameBLAS))
      lp->report(lp, NORMAL, "Optimized BLAS was successfully loaded for bfp_LUSOL.\n");
#endif

    /* Try to minimize memory allocation if we have a large number of unit columns */
    bsize = (REAL) lp->get_nonzeros(lp);
    if(newsize > lp->columns)
      bsize += newsize;
    else
      bsize = bsize/lp->columns*newsize;
    /* Add a "reasonable" delta to allow for B and associated factorizations
       that are denser than average; this makes reallocations less frequent.
       Values between 1.2 and 1.5 appear to be reasonable. */
    asize = (int) (bsize*MAX_DELTAFILLIN*1.3333);
    if(!LUSOL_sizeto(lu->LUSOL, newsize, newsize, asize))
      return( FALSE );
  }
  lu->dimcount = newsize;
  return( TRUE );
}
示例#16
0
int CurtisReidScales(lprec *lp, MYBOOL _Advanced, REAL *FRowScale, REAL *FColScale)
{
  int    i, row, col, ent, nz;
  REAL   *RowScalem2, *ColScalem2,
         *RowSum, *ColSum,
         *residual_even, *residual_odd;
  REAL   sk,   qk,     ek,
         skm1, qkm1,   ekm1,
         qkm2, qkqkm1, ekm2, ekekm1,
         absvalue, logvalue,
         StopTolerance;
  int    *RowCount, *ColCount, colMax;
  int    Result;
  MATrec *mat = lp->matA;
  REAL   *value;
  int    *rownr, *colnr;

  if(CurtisReidMeasure(lp, _Advanced, FRowScale, FColScale)<0.1*get_nonzeros(lp))
  return(0);

  /* Allocate temporary memory and find RowSum and ColSum measures */
  nz = get_nonzeros(lp);
  colMax = lp->columns;

  allocREAL(lp, &RowSum, lp->rows+1, TRUE);
  allocINT(lp,  &RowCount, lp->rows+1, TRUE);
  allocREAL(lp, &residual_odd, lp->rows+1, TRUE);

  allocREAL(lp, &ColSum, colMax+1, TRUE);
  allocINT(lp,  &ColCount, colMax+1, TRUE);
  allocREAL(lp, &residual_even, colMax+1, TRUE);

  allocREAL(lp, &RowScalem2, lp->rows+1, FALSE);
  allocREAL(lp, &ColScalem2, colMax+1, FALSE);

  /* Set origin for row scaling */
  for(i = 1; i <= colMax; i++) {
    absvalue=fabs(lp->orig_obj[i]);
    if(absvalue>0) {
      logvalue = log(absvalue);
      ColSum[i] += logvalue;
      RowSum[0] += logvalue;
      ColCount[i]++;
      RowCount[0]++;
    }
  }

  value = &(COL_MAT_VALUE(0));
  rownr = &(COL_MAT_ROWNR(0));
  colnr = &(COL_MAT_COLNR(0));
  for(i = 0; i < nz;
      i++, value += matValueStep, rownr += matRowColStep, colnr += matRowColStep) {
    absvalue=fabs(*value);
    if(absvalue>0) {
      logvalue = log(absvalue);
      ColSum[*colnr] += logvalue;
      RowSum[*rownr] += logvalue;
      ColCount[*colnr]++;
      RowCount[*rownr]++;
    }
  }

  /* Make sure we dont't have division by zero errors */
  for(row = 0; row <= lp->rows; row++)
    if(RowCount[row] == 0)
      RowCount[row] = 1;
  for(col = 1; col <= colMax; col++)
    if(ColCount[col] == 0)
      ColCount[col] = 1;

  /* Initialize to RowScale = RowCount-1 RowSum
                   ColScale = 0.0
                   residual = ColSum - ET RowCount-1 RowSum */

  StopTolerance= MAX(lp->scalelimit-floor(lp->scalelimit), DEF_SCALINGEPS);
  StopTolerance *= (REAL) nz;
  for(row = 0; row <= lp->rows; row++) {
    FRowScale[row] = RowSum[row] / (REAL) RowCount[row];
    RowScalem2[row] = FRowScale[row];
  }

  /* Compute initial residual */
  for(col = 1; col <= colMax; col++) {
    FColScale[col] = 0;
    ColScalem2[col] = 0;
    residual_even[col] = ColSum[col];

    if(lp->orig_obj[col] != 0)
      residual_even[col] -= RowSum[0] / (REAL) RowCount[0];

    i = mat->col_end[col-1];
    rownr = &(COL_MAT_ROWNR(i));
    ent = mat->col_end[col];
    for(; i < ent;
        i++, rownr += matRowColStep) {
      residual_even[col] -= RowSum[*rownr] / (REAL) RowCount[*rownr];
    }
  }

  /* Compute sk */
  sk = 0;
  skm1 = 0;
  for(col = 1; col <= colMax; col++)
    sk += (residual_even[col]*residual_even[col]) / (REAL) ColCount[col];

  Result = 0;
  qk=1; qkm1=0; qkm2=0;
  ek=0; ekm1=0; ekm2=0;

  while(sk>StopTolerance) {
  /* Given the values of residual and sk, construct
     ColScale (when pass is even)
     RowScale (when pass is odd)  */

    qkqkm1 = qk * qkm1;
    ekekm1 = ek * ekm1;
    if((Result % 2) == 0) { /* pass is even; construct RowScale[pass+1] */
      if(Result != 0) {
        for(row = 0; row <= lp->rows; row++)
          RowScalem2[row] = FRowScale[row];
        if(qkqkm1 != 0) {
          for(row = 0; row <= lp->rows; row++)
            FRowScale[row]*=(1 + ekekm1 / qkqkm1);
          for(row = 0; row<=lp->rows; row++)
            FRowScale[row]+=(residual_odd[row] / (qkqkm1 * (REAL) RowCount[row]) -
                             RowScalem2[row] * ekekm1 / qkqkm1);
        }
      }
    }
    else { /* pass is odd; construct ColScale[pass+1] */
      for(col = 1; col <= colMax; col++)
        ColScalem2[col] = FColScale[col];
      if(qkqkm1 != 0) {
        for(col = 1; col <= colMax; col++)
          FColScale[col] *= (1 + ekekm1 / qkqkm1);
        for(col = 1; col <= colMax; col++)
          FColScale[col] += (residual_even[col] / ((REAL) ColCount[col] * qkqkm1) -
                             ColScalem2[col] * ekekm1 / qkqkm1);
      }
    }

    /* update residual and sk (pass + 1) */
    if((Result % 2) == 0) { /* even */
       /* residual */
      for(row = 0; row <= lp->rows; row++)
        residual_odd[row] *= ek;

      for(i = 1; i <= colMax; i++)
        if(lp->orig_obj[i] != 0)
          residual_odd[0] += (residual_even[i] / (REAL) ColCount[i]);

      rownr = &(COL_MAT_ROWNR(0));
      colnr = &(COL_MAT_COLNR(0));
      for(i = 0; i < nz;
          i++, rownr += matRowColStep, colnr += matRowColStep) {
        residual_odd[*rownr] += (residual_even[*colnr] / (REAL) ColCount[*colnr]);
      }
      for(row = 0; row <= lp->rows; row++)
        residual_odd[row] *= (-1 / qk);

      /* sk */
      skm1 = sk;
      sk = 0;
      for(row = 0; row <= lp->rows; row++)
        sk += (residual_odd[row]*residual_odd[row]) / (REAL) RowCount[row];
    }
    else { /* odd */
      /* residual */
      for(col = 1; col <= colMax; col++)
        residual_even[col] *= ek;

      for(i = 1; i <= colMax; i++)
        if(lp->orig_obj[i] != 0)
          residual_even[i] += (residual_odd[0] / (REAL) RowCount[0]);

      rownr = &(COL_MAT_ROWNR(0));
      colnr = &(COL_MAT_COLNR(0));
      for(i = 0; i < nz;
          i++, rownr += matRowColStep, colnr += matRowColStep) {
        residual_even[*colnr] += (residual_odd[*rownr] / (REAL) RowCount[*rownr]);
      }
      for(col = 1; col <= colMax; col++)
        residual_even[col] *= (-1 / qk);

      /* sk */
      skm1 = sk;
      sk = 0;
      for(col = 1; col <= colMax; col++)
        sk += (residual_even[col]*residual_even[col]) / (REAL) ColCount[col];
    }

    /* Compute ek and qk */
    ekm2=ekm1;
    ekm1=ek;
    ek=qk * sk / skm1;

    qkm2=qkm1;
    qkm1=qk;
    qk=1-ek;

    Result++;
  }

  /* Synchronize the RowScale and ColScale vectors */
  ekekm1 = ek * ekm1;
  if(qkm1 != 0) {
  if((Result % 2) == 0) { /* pass is even, compute RowScale */
    for(row = 0; row<=lp->rows; row++)
      FRowScale[row]*=(1.0 + ekekm1 / qkm1);
    for(row = 0; row<=lp->rows; row++)
      FRowScale[row]+=(residual_odd[row] / (qkm1 * (REAL) RowCount[row]) -
                      RowScalem2[row] * ekekm1 / qkm1);
  }
  else { /* pass is odd, compute ColScale */
    for(col=1; col<=colMax; col++)
      FColScale[col]*=(1 + ekekm1 / qkm1);
    for(col=1; col<=colMax; col++)
      FColScale[col]+=(residual_even[col] / ((REAL) ColCount[col] * qkm1) -
                       ColScalem2[col] * ekekm1 / qkm1);
  }
  }

  /* Do validation, if indicated */
  if(FALSE && mat_validate(mat)){
    double check, error;

    /* CHECK: M RowScale + E ColScale = RowSum */
    error = 0;
    for(row = 0; row <= lp->rows; row++) {
      check = (REAL) RowCount[row] * FRowScale[row];
      if(row == 0) {
        for(i = 1; i <= colMax; i++) {
          if(lp->orig_obj[i] != 0)
            check += FColScale[i];
        }
      }
      else {
        i = mat->row_end[row-1];
        ent = mat->row_end[row];
        for(; i < ent; i++) {
          col = ROW_MAT_COLNR(i);
          check += FColScale[col];
        }
      }
      check -= RowSum[row];
      error += check*check;
    }

    /* CHECK: E^T RowScale + N ColScale = ColSum */
    error = 0;
    for(col = 1; col <= colMax; col++) {
      check = (REAL) ColCount[col] * FColScale[col];

      if(lp->orig_obj[col] != 0)
        check += FRowScale[0];

      i = mat->col_end[col-1];
      ent = mat->col_end[col];
      rownr = &(COL_MAT_ROWNR(i));
      for(; i < ent;
          i++, rownr += matRowColStep) {
        check += FRowScale[*rownr];
      }
      check -= ColSum[col];
      error += check*check;
    }
  }

  /* Convert to scaling factors (rounding to nearest power
     of 2 can optionally be done as a separate step later) */
  for(col = 1; col <= colMax; col++) {
    absvalue = exp(-FColScale[col]);
    if(absvalue < MIN_SCALAR) absvalue = MIN_SCALAR;
    if(absvalue > MAX_SCALAR) absvalue = MAX_SCALAR;
    if(!is_int(lp,col) || is_integerscaling(lp))
        FColScale[col] = absvalue;
    else
        FColScale[col] = 1;
  }
  for(row = 0; row <= lp->rows; row++) {
    absvalue = exp(-FRowScale[row]);
    if(absvalue < MIN_SCALAR) absvalue = MIN_SCALAR;
    if(absvalue > MAX_SCALAR) absvalue = MAX_SCALAR;
    FRowScale[row] = absvalue;
  }

 /* free temporary memory */
  FREE(RowSum);
  FREE(ColSum);
  FREE(RowCount);
  FREE(ColCount);
  FREE(residual_even);
  FREE(residual_odd);
  FREE(RowScalem2);
  FREE(ColScalem2);

  return(Result);

}
示例#17
0
STATIC MYBOOL restartPricer(lprec *lp, MYBOOL isdual)
{
  REAL   *sEdge = NULL, seNorm, hold;
  int    i, j, m;
  MYBOOL isDEVEX, ok = applyPricer(lp);
/* Correction from V6, apparently, via Kjell Eikland and the
** lpSolve mailing list 2014-06-18 2:57 p.m. */

  if (ok && (lp->edgeVector[0] < 0) && (isdual == AUTOMATIC))
    ok = FALSE;


  if(!ok)
    return( ok );

  /* Store the active/current pricing type */
  if(isdual == AUTOMATIC)
    isdual = (MYBOOL) lp->edgeVector[0];
  else
    lp->edgeVector[0] = isdual;

  m = lp->rows;

  /* Determine strategy and check if we have strategy fallback for the primal */
  isDEVEX = is_piv_rule(lp, PRICER_DEVEX);
  if(!isDEVEX && !isdual)
    isDEVEX = is_piv_mode(lp, PRICE_PRIMALFALLBACK);

  /* Check if we only need to do the simple DEVEX initialization */
  if(!is_piv_mode(lp, PRICE_TRUENORMINIT)) {
    if(isdual) {
      for(i = 1; i <= m; i++)
        lp->edgeVector[lp->var_basic[i]] = 1.0;
    }
    else {
      for(i = 1; i <= lp->sum; i++)
        if(!lp->is_basic[i])
          lp->edgeVector[i] = 1.0;
    }
    return( ok );
  }

  /* Otherwise do the full Steepest Edge norm initialization */
  ok = allocREAL(lp, &sEdge, m+1, FALSE);
  if(!ok)
    return( ok );

  if(isdual) {

   /* Extract the rows of the basis inverse and compute their squared norms */

    for(i = 1; i <= m; i++) {

      bsolve(lp, i, sEdge, NULL, 0, 0.0);

      /* Compute the edge norm */
      seNorm = 0;
      for(j = 1; j <= m; j++) {
        hold = sEdge[j];
        seNorm += hold*hold;
      }

      j = lp->var_basic[i];
      lp->edgeVector[j] = seNorm;
    }

  }
  else {

   /* Solve a=Bb for b over all non-basic variables and compute their squared norms */

    for(i = 1; i <= lp->sum; i++) {
      if(lp->is_basic[i])
        continue;

      fsolve(lp, i, sEdge, NULL, 0, 0.0, FALSE);

      /* Compute the edge norm */
      seNorm = 1;
      for(j = 1; j <= m; j++) {
        hold = sEdge[j];
        seNorm += hold*hold;
      }

      lp->edgeVector[i] = seNorm;
    }

  }

  FREE(sEdge);

  return( ok );

}
示例#18
0
/* Save a matrix column subset to a MatrixMarket formatted file,
   say to export the basis matrix for further numerical analysis.
   If colndx is NULL, then the full constraint matrix is assumed. */
MYBOOL REPORT_mat_mmsave(lprec *lp, char *filename, int *colndx, MYBOOL includeOF, char *infotext)
{
  int         n, m, nz, i, j, k, kk;
  MATrec      *mat = lp->matA;
  MM_typecode matcode;
  FILE        *output = stdout;
  MYBOOL      ok;
  LPSREAL        *acol = NULL;
  int         *nzlist = NULL;

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

  /* Compute column and non-zero counts */
  if(colndx == lp->var_basic) {
    if(!lp->basis_valid)
      return( FALSE );
    m = lp->rows;
  }
  else if(colndx != NULL)
    m = colndx[0];
  else
    m = lp->columns;
  n = lp->rows;
  nz = 0;

  for(j = 1; j <= m; j++) {
    k = (colndx == NULL ? n + j : colndx[j]);
    if(k > n) {
      k -= lp->rows;
      nz += mat_collength(mat, k);
      if(includeOF && is_OF_nz(lp, k))
        nz++;
    }
    else
      nz++;
  }
  kk = 0;
  if(includeOF) {
    n++;   /* Row count */
    kk++;  /* Row index offset */
  }

  /* Initialize */
  mm_initialize_typecode(&matcode);
  mm_set_matrix(&matcode);
  mm_set_coordinate(&matcode);
  mm_set_real(&matcode);

  mm_write_banner(output, matcode);
  mm_write_mtx_crd_size(output, n+kk, m, nz+(colndx == lp->var_basic ? 1 : 0));

  /* Allocate working arrays for sparse column storage */
  allocREAL(lp, &acol, n+2, FALSE);
  allocINT(lp, &nzlist, n+2, FALSE);

  /* Write the matrix non-zero values column-by-column.
     NOTE: matrixMarket files use 1-based indeces,
     i.e. first row of a vector has index 1, not 0. */
  if(infotext != NULL) {
    fprintf(output, "%%\n");
    fprintf(output, "%% %s\n", infotext);
    fprintf(output, "%%\n");
  }
  if(includeOF && (colndx == lp->var_basic))
    fprintf(output, "%d %d %g\n", 1, 1, 1.0);
  for(j = 1; j <= m; j++) {
    k = (colndx == NULL ? lp->rows + j : colndx[j]);
    if(k == 0)
      continue;
    nz = obtain_column(lp, k, acol, nzlist, NULL);
    for(i = 1; i <= nz; i++) {
      if(!includeOF && (nzlist[i] == 0))
        continue;
      fprintf(output, "%d %d %g\n", nzlist[i]+kk, j+kk, acol[i]);
    }
  }
  fprintf(output, "%% End of MatrixMarket file\n");

  /* Finish */
  FREE(acol);
  FREE(nzlist);
  fclose(output);

  return(ok);
}
示例#19
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 */