solve.c

来自「生成直角Steiner树的程序包」· C语言 代码 · 共 2,233 行 · 第 1/4 页

C
2,233
字号
static int solvelp(lprec *lp){  int    i, singular_count, lost_feas_count;  short  feasible;  REAL	 x;  if(lp->do_presolve)    presolve(lp);  lp->iter = 0;  singular_count = 0;  lost_feas_count = 0;  for(;;) {    /* Check whether we are feasible or infeasible. */    feasible = TRUE;    for(i = 1; i <= lp->rows; i++) {      x = lp->rhs[i];      if((x < 0) || (x > lp->upbo[lp->bas[i]])) {	feasible = FALSE;	break;      }    }    if(feasible) {      primloop(lp);    }    else {      dualloop(lp);      if(Status == SWITCH_TO_PRIMAL)	primloop(lp);    }    if(Status == SINGULAR_BASIS) {      ++singular_count;      if(singular_count >= 5) {	printf("%% SINGULAR BASIS!  Too many singularities - aborting.\n");	Status = FAILURE;	break;      }      printf("%% SINGULAR BASIS!  Will attempt to recover.\n");      /* Singular pivots are simply skipped by the inversion, leaving */      /* a row's slack var in the basis instead of the singular problem */      /* var.  This basis could be feasible or infeasible.  Check how to */      /* restart. */      continue;    }    else if(Status == LOST_PRIMAL_FEASIBILITY) {      ++lost_feas_count;      if(lost_feas_count >= 5) {	printf("%% LOST PRIMAL FEASIBILITY too many times, aborting.\n");	Status = FAILURE;	break;      }      printf("%% LOST PRIMAL FEASIBILITY!  Recovering.\n");      continue;    }    else {      /* One of the "normal" status codes -- we are done! */      break;    }  }  lp->total_iter += lp->iter;  return(Status);} /* solvelp */static short is_int(lprec *lp, int i){  REAL   value, error;  value = lp->solution[i];  error = value - (REAL)floor((double)value);  if(error < lp->epsilon)    return(TRUE);  if(error > (1 - lp->epsilon))    return(TRUE);  return(FALSE);} /* is_int */static void construct_solution(lprec *lp){  int    i, j, basi;  REAL   f;  /* zero all results of rows */  memset(lp->solution, '\0', (lp->rows + 1) * sizeof(REAL));  lp->solution[0] = -lp->orig_rh[0];  if(lp->scaling_used) {    lp->solution[0] /= lp->scale[0];    for(i = lp->rows + 1; i <= lp->sum; i++)      lp->solution[i] = lp->lowbo[i] * lp->scale[i];    for(i = 1; i <= lp->rows; i++) {      basi = lp->bas[i];      if(basi > lp->rows)	lp->solution[basi] += lp->rhs[i] * lp->scale[basi];    }    for(i = lp->rows + 1; i <= lp->sum; i++)      if(!lp->basis[i] && !lp->lower[i])	lp->solution[i] += lp->upbo[i] * lp->scale[i];    for(j = 1; j <= lp->columns; j++) {      f = lp->solution[lp->rows + j];      if(f != 0)	for(i = lp->col_end[j - 1]; i < lp->col_end[j]; i++)	  lp->solution[lp->mat[i].row_nr] += (f / lp->scale[lp->rows+j])	    * (lp->mat[i].value / lp->scale[lp->mat[i].row_nr]);    }    for(i = 0; i <= lp->rows; i++) {      if(my_abs(lp->solution[i]) < lp->epsb)	lp->solution[i] = 0;      else if(lp->ch_sign[i])	lp->solution[i] = -lp->solution[i];    }  }  else { /* no scaling */    for(i = lp->rows + 1; i <= lp->sum; i++)      lp->solution[i] = lp->lowbo[i];    for(i = 1; i <= lp->rows; i++) {      basi = lp->bas[i];      if(basi > lp->rows)	lp->solution[basi] += lp->rhs[i];    }    for(i = lp->rows + 1; i <= lp->sum; i++)      if(!lp->basis[i] && !lp->lower[i])	lp->solution[i] += lp->upbo[i];    for(j = 1; j <= lp->columns; j++) {      f = lp->solution[lp->rows + j];      if(f != 0)	for(i = lp->col_end[j - 1]; i < lp->col_end[j]; i++)	  lp->solution[lp->mat[i].row_nr] += f * lp->mat[i].value;    }    for(i = 0; i <= lp->rows; i++) {      if(my_abs(lp->solution[i]) < lp->epsb)	lp->solution[i] = 0;      else if(lp->ch_sign[i])	lp->solution[i] = -lp->solution[i];    }  }} /* construct_solution */static void calculate_duals(lprec *lp){  int i;  /* initialize */  lp->duals[0] = 1;  for(i = 1; i <= lp->rows; i++)    lp->duals[i] = 0;  btran(lp, lp->duals);  if(lp->scaling_used)    for(i = 1; i <= lp->rows; i++)      lp->duals[i] *= lp->scale[i] / lp->scale[0];  /* the dual values are the reduced costs of the slacks */  /* When the slack is at its upper bound, change the sign. */  for(i = 1; i <= lp->rows; i++) {    if(lp->basis[i])      lp->duals[i] = 0;    /* added a test if variable is different from 0 because sometime you get       -0 and this is different from 0 on for example INTEL processors (ie 0       != -0 on INTEL !) PN */    else if((lp->ch_sign[0] == lp->ch_sign[i]) && lp->duals[i])      lp->duals[i] = - lp->duals[i];  }} /* calculate_duals */static void check_if_less(REAL x,			  REAL y,			  REAL value){  if(x >= y) {    printf("%% Error: new upper or lower bound is not more restrictive\n");    printf("%% bound 1: %g, bound 2: %g, value: %g\n",	    (double)x, (double)y, (double)value);    /* exit(EXIT_FAILURE); */  }}static void check_solution(lprec *lp,			   REAL *upbo,			   REAL *lowbo){  int i;  /* check if all solution values are within the bounds, but allow some margin     for numerical errors */#define CHECK_EPS 1e-2  if(lp->columns_scaled)    for(i = lp->rows + 1; i <= lp->sum; i++) {      if(lp->solution[i] < lowbo[i] * lp->scale[i] - CHECK_EPS) {	printf("%% Error: variable %d (%s) has a solution (%g) smaller than its lower bound (%g)\n",		i - lp->rows, lp->col_name[i - lp->rows],		(double)lp->solution[i], (double)lowbo[i] * lp->scale[i]);	/* abort(); */      }      if(lp->solution[i] > upbo[i] * lp->scale[i] + CHECK_EPS) {	printf("%% Error: variable %d (%s) has a solution (%g) larger than its upper bound (%g)\n",		i - lp->rows, lp->col_name[i - lp->rows],		(double)lp->solution[i], (double)upbo[i] * lp->scale[i]);	/* abort(); */      }    }  else /* columns not scaled */    for(i = lp->rows + 1; i <= lp->sum; i++) {      if(lp->solution[i] < lowbo[i] - CHECK_EPS) {	printf("%% Error: variable %d (%s) has a solution (%g) smaller than its lower bound (%g)\n",		i - lp->rows, lp->col_name[i - lp->rows],		(double)lp->solution[i], (double)lowbo[i]);	/* abort(); */      }      if(lp->solution[i] > upbo[i] + CHECK_EPS) {	printf("%% Error: variable %d (%s) has a solution (%g) larger than its upper bound (%g)\n",		i - lp->rows, lp->col_name[i - lp->rows],		(double)lp->solution[i], (double)upbo[i]);	/* abort(); */      }    }} /* check_solution */static int milpsolve(lprec *lp,		     REAL   *upbo,		     REAL   *lowbo,		     short  *sbasis,		     short  *slower,		     int    *sbas,		     int     recursive){  int i, j, failure, notint, is_worse;  REAL theta, tmpreal;  if(Break_bb)    return(BREAK_BB);  Level++;  lp->total_nodes++;  if(Level > lp->max_level)    lp->max_level = Level;  debug_print(lp, "starting solve");  /* make fresh copies of upbo, lowbo, rh as solving changes them */  memcpy(lp->upbo,  upbo,    (lp->sum + 1)  * sizeof(REAL));  memcpy(lp->lowbo, lowbo,   (lp->sum + 1)  * sizeof(REAL));  memcpy(lp->rh,    lp->orig_rh, (lp->rows + 1) * sizeof(REAL));  /* make shure we do not do memcpy(lp->basis, lp->basis ...) ! */  if(recursive) {    memcpy(lp->basis, sbasis,  (lp->sum + 1)  * sizeof(short));    memcpy(lp->lower, slower,  (lp->sum + 1)  * sizeof(short));    memcpy(lp->bas,   sbas,    (lp->rows + 1) * sizeof(int));  }  if(lp->anti_degen) { /* randomly disturb bounds */    for(i = 1; i <= lp->columns; i++) {      tmpreal = (REAL) (rand() % 100 * 0.00001);      if(tmpreal > lp->epsb)	lp->lowbo[i + lp->rows] -= tmpreal;      tmpreal = (REAL) (rand() % 100 * 0.00001);      if(tmpreal > lp->epsb)	lp->upbo[i + lp->rows] += tmpreal;    }    lp->eta_valid = FALSE;  }  if(!lp->eta_valid) {    /* transform to all lower bounds to zero */    for(i = 1; i <= lp->columns; i++)      if((theta = lp->lowbo[lp->rows + i]) != 0) {	if(lp->upbo[lp->rows + i] < lp->infinite)	  lp->upbo[lp->rows + i] -= theta;	for(j = lp->col_end[i - 1]; j < lp->col_end[i]; j++)	  lp->rh[lp->mat[j].row_nr] -= theta * lp->mat[j].value;      }    invert(lp);    lp->eta_valid = TRUE;  }  failure = solvelp(lp);  if(lp->anti_degen && (failure == OPTIMAL)) {    /* restore to original problem, solve again starting from the basis found       for the disturbed problem */    /* restore original problem */    memcpy(lp->upbo,  upbo,        (lp->sum + 1)  * sizeof(REAL));    memcpy(lp->lowbo, lowbo,       (lp->sum + 1)  * sizeof(REAL));    memcpy(lp->rh,    lp->orig_rh, (lp->rows + 1) * sizeof(REAL));    /* transform to all lower bounds zero */    for(i = 1; i <= lp->columns; i++)      if((theta = lp->lowbo[lp->rows + i] != 0)) {	if(lp->upbo[lp->rows + i] < lp->infinite)	  lp->upbo[lp->rows + i] -= theta;	for(j = lp->col_end[i - 1]; j < lp->col_end[i]; j++)	  lp->rh[lp->mat[j].row_nr] -= theta * lp->mat[j].value;      }    invert(lp);    lp->eta_valid = TRUE;    failure = solvelp(lp); /* and solve again */  }  if(failure != OPTIMAL)    debug_print(lp, "this problem has no solution, it is %s",		(failure == UNBOUNDED) ? "unbounded" : "infeasible");  if(failure == INFEASIBLE && lp->verbose)    printf("%% level %d INF\n", Level);  if(failure == OPTIMAL) { /* there is a good solution */    construct_solution(lp);    /* because of reports of solution > upbo */    /* check_solution(lp, upbo, lowbo); get too many hits ?? */    debug_print(lp, "a solution was found");    debug_print_solution(lp);    /* if this solution is worse than the best sofar, this branch must die */    /* if we can only have integer OF values, we might consider requiring to       be at least 1 better than the best sofar, MB */    if(lp->maximise)      is_worse = lp->solution[0] <= lp->best_solution[0];    else /* minimising! */      is_worse = lp->solution[0] >= lp->best_solution[0];    if(is_worse) {      if(lp->verbose)	printf("%% level %d OPT NOB value %g bound %g\n",		Level, (double)lp->solution[0],		(double)lp->best_solution[0]);      debug_print(lp, "but it was worse than the best sofar, discarded");      Level--;      return(MILP_FAIL);    }    /* check if solution contains enough ints */    if(lp->bb_rule == FIRST_NI) {      for(notint = 0, i = lp->rows + 1;	  i <= lp->sum && notint == 0;	  i++) {	if(lp->must_be_int[i] && !is_int(lp, i)) {	  if(lowbo[i] == upbo[i]) { /* this var is already fixed */	    printf("%% Warning: integer var %d is already fixed at %d, but has non-integer value %g\n",		    i - lp->rows, (int)lowbo[i],		    (double)lp->solution[i]);	    printf("%% Perhaps the -e option should be used\n");	  }	  else	    notint = i;	}      }    }    if(lp->bb_rule == RAND_NI) {      int nr_not_int, select_not_int;      nr_not_int = 0;      for(i = lp->rows + 1; i <= lp->sum; i++)	if(lp->must_be_int[i] && !is_int(lp, i))	  nr_not_int++;      if(nr_not_int == 0)	notint = 0;      else {	select_not_int = (rand() % nr_not_int) + 1;	i = lp->rows + 1;	while(select_not_int > 0) {	  if(lp->must_be_int[i] && !is_int(lp, i))	    select_not_int--;	  i++;	}	notint = i - 1;      }    }    if(lp->verbose) {      if(notint)	printf("%% level %d OPT     value %g\n", Level,		(double)lp->solution[0]);      else	printf("%% level %d OPT INT value %g\n", Level,		(double)lp->solution[0]);    }    if(notint) { /* there is at least one value not yet int */      /* set up two new problems */      REAL   *new_upbo, *new_lowbo;      REAL   new_bound;      short  *new_lower,*new_basis;      int    *new_bas;      int     resone, restwo;      /* allocate room for them */      MALLOC(new_upbo,  lp->sum + 1);      MALLOC(new_lowbo, lp->sum + 1);      MALLOC(new_lower, lp->sum + 1);      MALLOC(new_basis, lp->sum + 1);      MALLOC(new_bas,   lp->rows + 1);      memcpy(new_upbo,  upbo,      (lp->sum + 1)  * sizeof(REAL));      memcpy(new_lowbo, lowbo,     (lp->sum + 1)  * sizeof(REAL));      memcpy(new_lower, lp->lower, (lp->sum + 1)  * sizeof(short));      memcpy(new_basis, lp->basis, (lp->sum + 1)  * sizeof(short));      memcpy(new_bas,   lp->bas,   (lp->rows + 1) * sizeof(int));      if(lp->names_used)	debug_print(lp, "not enough ints. Selecting var %s, val: %g",		    lp->col_name[notint - lp->rows],		    (double)lp->solution[notint]);      else	debug_print(lp,		    "not enough ints. Selecting Var [%d], val: %g",		    notint, (double)lp->solution[notint]);      debug_print(lp, "current bounds:\n");      debug_print_bounds(lp, upbo, lowbo);      if(lp->floor_first) {	new_bound = ceil(lp->solution[notint]) - 1;	/* this bound might conflict */	if(new_bound < lowbo[notint]) {	  debug_print(lp,		      "New upper bound value %g conflicts with old lower bound %g\n",		      (double)new_bound, (double)lowbo[notint]);	  resone = MILP_FAIL;	}	else { /* bound feasible */	  check_if_less(new_bound, upbo[notint], lp->solution[notint]);	  new_upbo[notint] = new_bound;	  debug_print(lp, "starting first subproblem with bounds:");	  debug_print_bounds(lp, new_upbo, lowbo);	  lp->eta_valid = FALSE;	  resone = milpsolve(lp, new_upbo, lowbo, new_basis, new_lower,			     new_bas, TRUE);	  lp->eta_valid = FALSE;	}	new_bound += 1;	if(new_bound > upbo[notint]) {	  debug_print(lp,		      "New lower bound value %g conflicts with old upper bound %g\n",		      (double)new_bound, (double)upbo[notint]);	  restwo = MILP_FAIL;	}	else { /* bound feasible */	  check_if_less(lowbo[notint], new_bound, lp->solution[notint]);	  new_lowbo[notint] = new_bound;	  debug_print(lp, "starting second subproblem with bounds:");	  debug_print_bounds(lp, upbo, new_lowbo);	  lp->eta_valid = FALSE;	  restwo = milpsolve(lp, upbo, new_lowbo, new_basis, new_lower,			     new_bas, TRUE);	  lp->eta_valid = FALSE;	}      }      else { /* take ceiling first */	new_bound = ceil(lp->solution[notint]);	/* this bound might conflict */	if(new_bound > upbo[notint]) {	  debug_print(lp,		      "New lower bound value %g conflicts with old upper bound %g\n",		      (double)new_bound, (double)upbo[notint]);	  resone = MILP_FAIL;	}	else { /* bound feasible */	  check_if_less(lowbo[notint], new_bound, lp->solution[notint]);	  new_lowbo[notint] = new_bound;	  debug_print(lp, "starting first subproblem with bounds:");	  debug_print_bounds(lp, upbo, new_lowbo);	  lp->eta_valid = FALSE;	  resone = milpsolve(lp, upbo, new_lowbo, new_basis, new_lower,			     new_bas, TRUE);	  lp->eta_valid = FALSE;	}	new_bound -= 1;	if(new_bound < lowbo[notint]) {	  debug_print(lp,		      "New upper bound value %g conflicts with old lower bound %g\n",		      (double)new_bound, (double)lowbo[notint]);	  restwo = MILP_FAIL;	}	else { /* bound feasible */	  check_if_less(new_bound, upbo[notint], lp->solution[notint]);	  new_upbo[notint] = new_bound;	  debug_print(lp, "starting second subproblem with bounds:");	  debug_print_bounds(lp, new_upbo, lowbo);	  lp->eta_valid = FALSE;	  restwo = milpsolve(lp, new_upbo, lowbo, new_basis, new_lower,			     new_bas, TRUE);	  lp->eta_valid = FALSE;	}      }      if(resone && restwo) /* both failed and must have been infeasible */	failure = INFEASIBLE;      else	failure = OPTIMAL;      free(new_upbo);      free(new_lowbo);      free(new_basis);      free(new_lower);      free(new_bas);    }    else { /* all required values are int */      debug_print(lp, "--> valid solution found");      if(lp->maximise)	is_worse = lp->solution[0] < lp->best_solution[0];      else	is_worse = lp->solution[0] > lp->best_solution[0];      if(!is_worse) { /* Current solution better */	if(lp->debug || (lp->verbose && !lp->print_sol))	  printf("%% *** new best solution: old: %g, new: %g ***\n",		  (double)lp->best_solution[0], (double)lp->solution[0]);	memcpy(lp->best_solution, lp->solution, (lp->sum + 1) * sizeof(REAL));	calculate_duals(lp);	if(lp->print_sol)	  print_solution(lp);	if(lp->break_at_int) {	  if(lp->maximise && (lp->best_solution[0] > lp->break_value))	    Break_bb = TRUE;	  if(!lp->maximise && (lp->best_solution[0] < lp->break_value))	    Break_bb = TRUE;	}      }    }  }  Level--;  /* failure can have the values OPTIMAL, UNBOUNDED and INFEASIBLE. */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?