solve.c

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

C
2,233
字号
  return(failure);} /* milpsolve */int solve(lprec *lp){  int result, i;  lp->total_iter  = 0;  lp->max_level   = 1;  lp->total_nodes = 0;  if(isvalid(lp)) {    if(lp->maximise && lp->obj_bound == lp->infinite)      lp->best_solution[0] = -lp->infinite;    else if(!lp->maximise && lp->obj_bound == -lp->infinite)      lp->best_solution[0] = lp->infinite;    else      lp->best_solution[0] = lp->obj_bound;    Level = 0;    if(!lp->basis_valid) {      for(i = 0; i <= lp->rows; i++) {	lp->basis[i] = TRUE;	lp->bas[i]   = i;      }      for(i = lp->rows + 1; i <= lp->sum; i++)	lp->basis[i] = FALSE;      for(i = 0; i <= lp->sum; i++)	lp->lower[i] = TRUE;      lp->basis_valid = TRUE;    }    lp->eta_valid = FALSE;    Break_bb      = FALSE;    result        = milpsolve(lp, lp->orig_upbo, lp->orig_lowbo, lp->basis,			      lp->lower, lp->bas, FALSE);    return(result);  }  /* if we get here, isvalid(lp) failed. I suggest we return FAILURE */  printf("%% Error, the current LP seems to be invalid\n");  return(FAILURE);} /* solve *//* * This routine saves the current basis of the given LP. */	voidsave_LP_basis (lprec *			lp,		/* IN - LP to save basis for */struct basis_save *	basp		/* OUT - saved basis info */){int		i;int		j;int		varnr;int		rows;int		sum;double		theta;	if (!lp->row_end_valid)		set_row_end (lp);	/* Re-initialize the various versions of things needed	*/	/* to re-invert...					*/	memcpy (lp->upbo,	lp->orig_upbo,	(lp->sum + 1) * sizeof (REAL));	memcpy (lp->lowbo,	lp->orig_lowbo,	(lp->sum + 1) * sizeof (REAL));	memcpy (lp->rh,		lp->orig_rh,	(lp->rows + 1) * sizeof (REAL));	/* Process non-zero lower bounds... */	for (i = 1; i <= lp->columns; i++) {		varnr = lp->rows + i;		theta = lp->lowbo[varnr];		if (theta != 0.0) {			if (lp->upbo[varnr] < lp->infinite) {				lp->upbo[varnr] -= 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;			}		}	}	/* First things first -- reinvert so that the eta	*/	/* vectors are as simple as possible before we save...	*/	invert (lp);	lp -> eta_valid = TRUE;	rows	= lp -> rows;	sum	= lp -> sum;	/* Allocate buffers to save state into... */	CALLOC (basp -> bas, rows + 1);	CALLOC (basp -> basis, sum + 1);	CALLOC (basp -> lower, sum + 1);	CALLOC (basp -> rhs, rows + 1);	CALLOC (basp -> drow, sum + 1);	CALLOC (basp -> prow, sum + 1);	CALLOC (basp -> Pcol, rows + 1);	/* Save the basis state info... */	basp -> eta_size = lp -> eta_size;	memcpy (basp -> bas, lp -> bas, (rows + 1) * sizeof (int));	memcpy (basp -> basis, lp -> basis, (sum + 1) * sizeof (short));	memcpy (basp -> lower, lp -> lower, (sum + 1) * sizeof (short));	memcpy (basp -> rhs, lp -> rhs, (rows + 1) * sizeof (REAL));}/* * Destroy the saved basis info... */	voiddestroy_LP_basis (struct basis_save *	basp		/* IN - basis info to free up */){	free ((char *) (basp -> Pcol));	free ((char *) (basp -> prow));	free ((char *) (basp -> drow));	free ((char *) (basp -> rhs));	free ((char *) (basp -> lower));	free ((char *) (basp -> basis));	free ((char *) (basp -> bas));}/* * This routine performs a quick "test run" of branching the given * variable in the given direction.  We start from the current basis * (which has been saved in basp, and is assumed optimal), and do at * most 50 or so iterations -- but NEVER reinverting, which would * clobber the saved eta vectors...  This means we can restore the * eta just by popping back to the initial eta size. */	REALtry_branch (lprec *			lp,	/* IN - LP to test branching for */int			var,	/* IN - variable to branch */int			dir,	/* IN - direction to branch in, 0 or 1 */REAL *			x,	/* OUT - LP solution found */REAL			ival,	/* IN - value to yield if infeasible */struct basis_save *	basp	/* IN - basis to restore when done */){int		i;int		j;int		varnr;REAL		f;REAL		theta;short		primal;REAL *		drow;REAL *		prow;REAL *		Pcol;REAL		save_lb;REAL		save_ub;short		minit;int		colnr;int		row_nr;	lp -> total_iter	= 0;	lp -> max_level		= 1;	lp -> total_nodes	= 0;	if ((var < 1) ||	    (var > lp -> columns) ||	    !isvalid (lp) ||	    (lp -> scaling_used) ||	    !(lp -> basis_valid) ||	    !(lp -> eta_valid) ||	    !(lp -> basis [lp->rows + var])) {		fprintf (stderr, "Bad call to try_branch...\n");		abort ();	}	Level = 1;	drow	= basp -> drow;	prow	= basp -> prow;	Pcol	= basp -> Pcol;	lp -> iter = 0;	minit = FALSE;	Status = RUNNING;	DoInvert = FALSE;	Doiter = FALSE;	/* We assume the caller starts us from an optimal basis, from	*/	/* which we branch (up or down), creating an infeasibility.	*/	/* Thus after branching we always use the Dual Simplex...	*/	varnr = lp -> rows + var;	save_lb = lp -> lowbo [varnr];	save_ub = lp -> upbo [varnr];	if (dir == 0) {		/* Branching down -- fix upper bound and continue	*/		/* optimizing from the same tableaux...			*/		lp -> upbo [varnr] = 0.0;	}	else {		/* Branching up -- adjust rhs.  The branching variable	*/		/* MUST be basis!  (We verified this above.)  Therefore	*/		/* there is only a single RHS value that we need to	*/		/* adjust because this variables column is all zeros	*/		/* except for a one in the row in which it is basic.	*/		lp -> lowbo [varnr] = 1.0;		lp -> upbo [varnr] = 0.0;		for (i = 1; ; i++) {			if (i > lp -> rows) {				fprintf (stderr, "try_branch: Bug 1.\n");				abort ();			}			if (lp -> bas [i] == varnr) {				lp -> rhs [i] -= 1.0;				break;			}		}		/* Fix up objective function value also! */		for (j = lp -> col_end [var - 1]; j < lp -> col_end [var]; j++) {			if (lp -> mat [j].row_nr == 0) {				lp -> rhs [0] -= lp -> mat [j].value;				break;			}		}	}	primal = FALSE;	/* Get most negative INITIAL objective coefficient into	*/	/* Extrad...						*/	drow [0] = 1;	for (i = 1; i <= lp -> rows; i++) {		drow [i] = 0;	}	Extrad = 0;	for (i = 1; i <= lp -> columns; i++) {		varnr = lp -> rows + i;		drow [varnr] = 0;		for (j = lp -> col_end [i - 1]; j < lp -> col_end [i]; j++) {			if (drow [lp -> mat[j].row_nr] != 0) {				drow [varnr] +=					drow [lp -> mat [j].row_nr]					* lp -> mat [j].value;			}		}		if (drow [varnr] < Extrad) {			Extrad = drow [varnr];		}	}	if (lp -> trace) {		printf ("%% Extrad = %f\n", Extrad);	}	row_nr = 0;	colnr = 0;	minit = FALSE;	while (Status == RUNNING) {		Doiter = FALSE;		DoInvert = FALSE;		if (!minit) {			row_nr = rowdual (lp);		}		if (row_nr > 0 ) {			colnr = coldual (lp, row_nr, minit, prow, drow);			if (colnr > 0) {				setpivcol (lp, colnr, Pcol);				/* getting div by zero here ... MB */				if (Pcol [row_nr] == 0) {					printf ("%% An attempt was made to divide by zero (Pcol[%d])\n",						 row_nr);					printf ("%% This indicates numerical instability\n");					Doiter = FALSE;					Status = STOP_AT_INVERT;				}				else {					condensecol (lp, row_nr, Pcol);					f = lp -> rhs [row_nr]						- lp -> upbo [lp -> bas [row_nr]];					if (f > 0) {						theta = f / (REAL) Pcol [row_nr];						if (theta <= lp -> upbo [colnr] + lp -> epsb) {							lp -> lower [lp -> bas [row_nr]]								= !lp -> lower [lp -> bas [row_nr]];						}					}					else { /* f <= 0 */						theta = lp -> rhs [row_nr] / (REAL) Pcol [row_nr];					}				}			}			else {				Status = INFEASIBLE;			}		}		else {			/* Assume optimal achieved... */			Doiter   = FALSE;			DoInvert = TRUE;		}		if (Doiter) {			iteration (lp,				   row_nr,				   colnr,				   &theta,				   lp -> upbo [colnr],				   &minit,				   &(lp -> lower [colnr]),				   primal,				   Pcol);		}		if (lp -> num_inv >= lp -> max_num_inv) {			DoInvert = TRUE;		}		if (DoInvert) {			/* We DO NOT invert!  That would mess up the	*/			/* eta vectors that we want to restore back to!	*/			/* Instead we just stop here and we are done!	*/			Status = STOP_AT_INVERT;		}	}	lp -> total_iter += lp -> iter;	construct_solution (lp);	memcpy (x,		&(lp -> solution [lp -> rows + 1]),		lp -> columns * sizeof (REAL));	/* Restore the LP state back to the saved basis... */	varnr = lp -> rows + var;	lp -> lowbo [varnr] = save_lb;	lp -> upbo [varnr] = save_ub;	lp -> eta_size = basp -> eta_size;	memcpy (lp -> bas, basp -> bas, (lp -> rows + 1) * sizeof (int));	memcpy (lp -> basis, basp -> basis, (lp -> sum + 1) * sizeof (short));	memcpy (lp -> lower, basp -> lower, (lp -> sum + 1) * sizeof (short));	memcpy (lp -> rhs, basp -> rhs, (lp -> rows + 1) * sizeof (REAL));	if (Status == INFEASIBLE) {		return (ival);	}	return (lp -> solution [0]);}int lag_solve(lprec *lp, REAL start_bound, int num_iter, short verbose){  int i, j, result, citer;  short status, OrigFeas, AnyFeas, same_basis;  REAL *OrigObj, *ModObj, *SubGrad, *BestFeasSol;  REAL Zub, Zlb, Ztmp, pie;  REAL rhsmod, Step, SqrsumSubGrad;  int   *old_bas;  short *old_lower;  /* allocate mem */  MALLOC(OrigObj, lp->columns + 1);  CALLOC(ModObj, lp->columns + 1);  CALLOC(SubGrad, lp->nr_lagrange);  CALLOC(BestFeasSol, lp->sum + 1);  MALLOCCPY(old_bas, lp->bas, lp->rows + 1);  MALLOCCPY(old_lower, lp->lower, lp->sum + 1);  get_row(lp, 0, OrigObj);  pie = 2;  if(lp->maximise) {    Zub = DEF_INFINITE;    Zlb = start_bound;  }  else {    Zlb = -DEF_INFINITE;    Zub = start_bound;  }  status   = RUNNING;  Step     = 1;  OrigFeas = FALSE;  AnyFeas  = FALSE;  citer    = 0;  for(i = 0 ; i < lp->nr_lagrange; i++)    lp->lambda[i] = 0;  while(status == RUNNING) {    citer++;    for(i = 1; i <= lp->columns; i++) {      ModObj[i] = OrigObj[i];      for(j = 0; j < lp->nr_lagrange; j++) {	if(lp->maximise)	  ModObj[i] -= lp->lambda[j] * lp->lag_row[j][i];	else	  ModObj[i] += lp->lambda[j] * lp->lag_row[j][i];      }    }    for(i = 1; i <= lp->columns; i++) {      set_mat(lp, 0, i, ModObj[i]);    }    rhsmod = 0;    for(i = 0; i < lp->nr_lagrange; i++)      if(lp->maximise)	rhsmod += lp->lambda[i] * lp->lag_rhs[i];      else	rhsmod -= lp->lambda[i] * lp->lag_rhs[i];    if(verbose) {      printf("%% Zub: %10g Zlb: %10g Step: %10g pie: %10g Feas %d\n",	      (double)Zub, (double)Zlb, (double)Step, (double)pie, OrigFeas);      for(i = 0; i < lp->nr_lagrange; i++)	printf("%% %3d SubGrad %10g lambda %10g\n", i,		(double)SubGrad[i], (double)lp->lambda[i]);    }    if(verbose && lp->sum < 20)      print_lp(lp);    result = solve(lp);    if(verbose && lp->sum < 20) {      print_solution(lp);    }    same_basis = TRUE;    i = 1;    while(same_basis && i < lp->rows) {      same_basis = (old_bas[i] == lp->bas[i]);      i++;    }    i = 1;    while(same_basis && i < lp->sum) {      same_basis=(old_lower[i] == lp->lower[i]);      i++;    }    if(!same_basis) {      memcpy(old_lower, lp->lower, (lp->sum+1) * sizeof(short));      memcpy(old_bas, lp->bas, (lp->rows+1) * sizeof(int));      pie *= 0.95;    }    if(verbose)      printf("%% result: %d  same basis: %d\n", result, same_basis);    if(result == UNBOUNDED) {      for(i = 1; i <= lp->columns; i++)	printf("%g ", (double)ModObj[i]);      exit(EXIT_FAILURE);    }    if(result == FAILURE)      status = FAILURE;    if(result == INFEASIBLE)      status = INFEASIBLE;    SqrsumSubGrad = 0;    for(i = 0; i < lp->nr_lagrange; i++) {      SubGrad[i]= -lp->lag_rhs[i];      for(j = 1; j <= lp->columns; j++)	SubGrad[i] += lp->best_solution[lp->rows + j] * lp->lag_row[i][j];      SqrsumSubGrad += SubGrad[i] * SubGrad[i];    }    OrigFeas = TRUE;    for(i = 0; i < lp->nr_lagrange; i++)      if(lp->lag_con_type[i]) {	if(my_abs(SubGrad[i]) > lp->epsb)	  OrigFeas = FALSE;      }      else if(SubGrad[i] > lp->epsb)	OrigFeas = FALSE;    if(OrigFeas) {      AnyFeas = TRUE;      Ztmp = 0;      for(i = 1; i <= lp->columns; i++)	Ztmp += lp->best_solution[lp->rows + i] * OrigObj[i];      if((lp->maximise) && (Ztmp > Zlb)) {	Zlb = Ztmp;	for(i = 1; i <= lp->sum; i++)	  BestFeasSol[i] = lp->best_solution[i];	BestFeasSol[0] = Zlb;	if(verbose)	  printf("%% Best feasible solution: %g\n", (double)Zlb);      }      else if(Ztmp < Zub) {	Zub = Ztmp;	for(i = 1; i <= lp->sum; i++)	  BestFeasSol[i] = lp->best_solution[i];	BestFeasSol[0] = Zub;	if(verbose)	  printf("%% Best feasible solution: %g\n", (double)Zub);      }        }    if(lp->maximise)      Zub = my_min(Zub, rhsmod + lp->best_solution[0]);    else      Zlb = my_max(Zlb, rhsmod + lp->best_solution[0]);    if(my_abs(Zub-Zlb)<0.001) {      status = OPTIMAL;    }    Step = pie * ((1.05*Zub) - Zlb) / SqrsumSubGrad;    for(i = 0; i < lp->nr_lagrange; i++) {      lp->lambda[i] += Step * SubGrad[i];      if(!lp->lag_con_type[i] && lp->lambda[i] < 0)	lp->lambda[i] = 0;    }    if(citer == num_iter && status==RUNNING) {      if(AnyFeas)	status = FEAS_FOUND;      else	status = NO_FEAS_FOUND;    }  }  for(i = 0; i <= lp->sum; i++)    lp->best_solution[i] = BestFeasSol[i];  for(i = 1; i <= lp->columns; i++)    set_mat(lp, 0, i, OrigObj[i]);  if(lp->maximise)    lp->lag_bound = Zub;  else    lp->lag_bound = Zlb;  free(BestFeasSol);  free(SubGrad);  free(OrigObj);  free(ModObj);  free(old_bas);  free(old_lower);  return(status);}

⌨️ 快捷键说明

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