示例#1
0
void SSCplex::ChgPrType(int type)
{
  //  int status = CPXchgprobtype(env,lp,type);
  //  int status = CPXchgprobtype(env,lp,CPXPROB_RELAXED);
  int status = CPXchgprobtype(env,lp,2);
  if(!status) cout << "Error while solving problem type" << endl;
}
示例#2
0
//==========================================================================
// Restore bounds and type of the first stage variables
int
DDSIP_RestoreBoundAndType (void)
{
    int status = 0;

    if ((DDSIP_bb->DDSIP_step == neobj || DDSIP_bb->DDSIP_step == eev) && DDSIP_param->riskvar)
        DDSIP_UndeleteRiskObj ();

    // Restore original bounds
    status = CPXchgbds (DDSIP_env, DDSIP_lp, DDSIP_bb->firstvar, DDSIP_bb->firstindex, DDSIP_bb->lbident, DDSIP_bb->lborg);
    if (status)
    {
        fprintf (stderr, "ERROR: Failed to change lower bounds \n");
        return status;
    }

    status = CPXchgbds (DDSIP_env, DDSIP_lp, DDSIP_bb->firstvar, DDSIP_bb->firstindex, DDSIP_bb->ubident, DDSIP_bb->uborg);
    if (status)
    {
        fprintf (stderr, "ERROR: Failed to change upper bounds \n");
        return status;
    }
    // probtype=0 (LP)
    if (!CPXgetprobtype (DDSIP_env, DDSIP_lp))
    {
        status = CPXchgprobtype (DDSIP_env, DDSIP_lp, CPXPROB_MILP);
        if (status)
        {
            fprintf (stderr, "ERROR: Failed to change problem type (Restore) \n");
            return status;
        }
        status = CPXchgctype (DDSIP_env, DDSIP_lp, DDSIP_bb->secvar, DDSIP_bb->secondindex, DDSIP_bb->sectype);
        if (status)
        {
            fprintf (stderr, "ERROR: Failed to change types of second-stage variables (Restore) \n");
            return status;
        }
    }
    //Restore ctypes if solving was processed with relaxed first stage
    if (DDSIP_bb->DDSIP_step == solve && DDSIP_param->relax == 1)
    {
        status = CPXchgctype (DDSIP_env, DDSIP_lp, DDSIP_bb->firstvar, DDSIP_bb->firstindex, DDSIP_bb->firsttype);
        if (status)
        {
            fprintf (stderr, "ERROR: Failed to change types of first stage variables (Restore) \n");
            return status;
        }
    }
    return status;
}
示例#3
0
// Starts the CPLEX environment
CPLEX cplex_start() {
  int status;
  CPXENVptr env = CPXopenCPLEX(&status);
  
  // disable screen solution and data consistency checking for speed
  CPXsetintparam(env, CPX_PARAM_SCRIND, CPX_OFF);
  CPXsetintparam(env, CPX_PARAM_DATACHECK, CPX_OFF);
  
  CPXLPptr lp = CPXcreateprob(env, &status, "tsp");
  CPXchgprobtype(env, lp, CPXPROB_MILP); // mixed integer problem
  CPXchgobjsen(env, lp, CPX_MIN); // objective is minimization
  
  //CPXwriteprob(env, lp, "problem.lp", "LP");
  
  CPLEX cplex = {env, lp, &status};
  
  return cplex;
}
示例#4
0
int CPLEXAddConstraint(LinEquation* InEquation) {
	int Status = 0;
	
	if (InEquation->ConstraintType != QUADRATIC && InEquation->ConstraintType != LINEAR) {
		FErrorFile() << "This constraint type is not supported in CPLEX: " << InEquation->ConstraintType << endl;
		FlushErrorFile();
		return FAIL;
	}

	//First I check the number of rows. If it's larger than the index, then this constraint already exists and is only being changed
	int NumberRows = CPXgetnumrows (CPLEXenv, CPLEXModel);
	if (NumberRows <= InEquation->Index) {
		char* Sense = new char[1];
		if (InEquation->EqualityType == EQUAL) {
			if (InEquation->QuadOne.size() > 0) {
				delete [] Sense;
				FErrorFile() << "Quadratic constraints cannot be equivalent constraints in CPLEX." << endl;
				FlushErrorFile();
				return FAIL;
			} else {
				Sense[0] = 'E';
			}
		} else if (InEquation->EqualityType == LESS) {
			Sense[0] = 'L';
		} else if (InEquation->EqualityType == GREATER) {
			Sense[0] = 'G';
		} else {
			delete [] Sense;
			FErrorFile() << "Unrecognized constraint type: " << InEquation->ConstraintType << endl;
			FlushErrorFile();
			return FAIL;
		}

		double* Rhs = new double[1];
		Rhs[0] = InEquation->RightHandSide;
		
		int* ColInd = NULL;
		int* RowInd = NULL;
		double* Coeff = NULL;
		if (InEquation->Variables.size() > 0) {
			ColInd = new int[int(InEquation->Variables.size())];
			RowInd = new int[int(InEquation->Variables.size())];
			Coeff = new double[int(InEquation->Variables.size())];
			for (int i=0; i < int(InEquation->Variables.size()); i++) {
				Coeff[i] = InEquation->Coefficient[i];
				RowInd[i] = 0;
				ColInd[i] = InEquation->Variables[i]->Index;
			}
		}
		
		if (InEquation->QuadOne.size() > 0) {
			if (CPXgetprobtype(CPLEXenv, CPLEXModel) == CPXPROB_LP) {
				Status = CPXchgprobtype(CPLEXenv, CPLEXModel, CPXPROB_QP);
			}
			else if (CPXgetprobtype(CPLEXenv, CPLEXModel) == CPXPROB_MILP) {
				Status = CPXchgprobtype(CPLEXenv, CPLEXModel, CPXPROB_MIQP);
			}
	
			int *QuadCol = new int[int(InEquation->QuadOne.size())];
			int *QuadRow = new int[int(InEquation->QuadTwo.size())];
			double *QuadCoeff = new double[int(InEquation->QuadCoeff.size())];
			for (int i=0; i < int(InEquation->QuadOne.size()); i++) {
				QuadCol[i] = InEquation->QuadOne[i]->Index;
				QuadRow[i] = InEquation->QuadTwo[i]->Index;
				QuadCoeff[i] = InEquation->QuadCoeff[i];
			}

			Status = CPXaddqconstr(CPLEXenv, CPLEXModel, int(InEquation->Variables.size()), int(InEquation->QuadOne.size()), Rhs[0], int(Sense[0]), ColInd, Coeff, QuadRow, QuadCol, QuadCoeff, NULL);

			delete [] QuadCol;
			delete [] QuadRow;
			delete [] QuadCoeff;
		} else if (InEquation->Variables.size() > 0) {	
			string StrName = GetConstraintName(InEquation);
			char** Name = new char*;
			Name[0] = new char[StrName.length()+1];
			strcpy(Name[0],StrName.data());

			if ((InEquation->ConstraintMeaning.compare("chemical potential constraint") == 0) && (InEquation->Loaded == false) && (GetParameter("Check potential constraints feasibility").compare("1") == 0)) {
				Rhs[0] = InEquation->LoadedRightHandSide;
				Sense[0] = 'L';
			} else if ((InEquation->ConstraintMeaning.compare("chemical potential constraint") == 0) && (InEquation->Loaded == false) && (InEquation->RightHandSide > 0.9*FLAG)){
				Rhs[0] = FLAG;
				Sense[0] = 'L';
			}

			Status = CPXaddrows(CPLEXenv, CPLEXModel, 0, 1, int(InEquation->Variables.size()), Rhs, Sense, RowInd, ColInd, Coeff, NULL, Name);
			delete [] Name[0];
			delete [] Name;
			delete [] ColInd;
			delete [] RowInd;
			delete [] Coeff;	
		}
		delete [] Rhs;
		delete [] Sense;

		if (Status) {
			FErrorFile() << "Failed to add constraint: " << InEquation->Index << endl;
			FlushErrorFile();
			return FAIL;
		}
	} else {
		if (InEquation->QuadOne.size() > 0) {
			FErrorFile() << "Cannot change a quadratic constraint." << endl;
			FlushErrorFile();
			return FAIL;
		} else {
			int NumberOfColumns = CPXgetnumcols(CPLEXenv, CPLEXModel);
			//First I reset all of the coefficients to zero
			for (int i=0; i < NumberOfColumns; i++) {
				Status = CPXchgcoef (CPLEXenv, CPLEXModel, InEquation->Index, i, 0);
				if (Status) {
					FErrorFile() << "Failed to change constraint: " << InEquation->Index << endl;
					FlushErrorFile();
					return FAIL;
				}
			}
			//Next I set all of the nonzero coefficients according to the input equation
			for (int i=0; i < int(InEquation->Variables.size()); i++) {
				Status = CPXchgcoef (CPLEXenv, CPLEXModel, InEquation->Index, InEquation->Variables[i]->Index, InEquation->Coefficient[i]);
				if (Status) {
					FErrorFile() << "Failed to change constraint: " << InEquation->Index << endl;
					FlushErrorFile();
					return FAIL;
				}
			}
			
			char* Sense = new char[1];
			
			if (InEquation->ConstraintMeaning.compare("chemical potential constraint") == 0 && InEquation->Loaded == false) {
				Sense[0] = 'L';
				
				Status = CPXchgcoef (CPLEXenv, CPLEXModel, InEquation->Index, -1, InEquation->LoadedRightHandSide);
				Status = CPXchgsense (CPLEXenv, CPLEXModel, 1, &(InEquation->Index), Sense);
				
			} else {
			
				//Now I change the RHS of the constraint
				Status = CPXchgcoef (CPLEXenv, CPLEXModel, InEquation->Index, -1, InEquation->RightHandSide);
	
				//Also change the sense of the constraint if nec
				
				if (InEquation->EqualityType == EQUAL) {
					if (InEquation->QuadOne.size() > 0) {
						delete [] Sense;
						FErrorFile() << "Quadratic constraints cannot be equivalent constraints in CPLEX." << endl;
						FlushErrorFile();
						return FAIL;
					} else {
						Sense[0] = 'E';
					}
				} else if (InEquation->EqualityType == LESS) {
					Sense[0] = 'L';
				} else if (InEquation->EqualityType == GREATER) {
					Sense[0] = 'G';
				} else {
					delete [] Sense;
					FErrorFile() << "Unrecognized constraint type: " << InEquation->ConstraintType << endl;
					FlushErrorFile();
					return FAIL;
				}
	
				Status = CPXchgsense (CPLEXenv, CPLEXModel, 1, &(InEquation->Index), Sense);
				if (Status) {
					FErrorFile() << "Failed to change constraint: " << InEquation->Index << endl;
					FlushErrorFile();
					return FAIL;
				}
			}
		}
	}
	return SUCCESS;
}
示例#5
0
int CPLEXLoadObjective(LinEquation* InEquation, bool Max) {
	int NumCols = CPXgetnumcols(CPLEXenv, CPLEXModel);
	int Status = 0;

	if (Max) {
		CPXchgobjsen (CPLEXenv, CPLEXModel, CPX_MAX);
	} else {
		CPXchgobjsen (CPLEXenv, CPLEXModel, CPX_MIN);
	}
	
	int* Indeces = new int[NumCols];
	double* Coeffs = new double[NumCols];

	for (int i=0; i < NumCols; i++) {
		Indeces[i] = i;
		Coeffs[i] = 0;
	}
	for (int i=0; i < int(InEquation->Variables.size()); i++) {
		Coeffs[InEquation->Variables[i]->Index] = InEquation->Coefficient[i];
	}
	
	Status = CPXchgobj(CPLEXenv, CPLEXModel, NumCols, Indeces, Coeffs);
	delete [] Indeces;
	delete [] Coeffs;
	if (Status) {
		cout << "Failed to set objective coefficients. " << endl;
		return FAIL;
	}
	if (InEquation->QuadOne.size() > 0) {
		if (CPXgetprobtype(CPLEXenv, CPLEXModel) == CPXPROB_LP) {
			Status = CPXchgprobtype(CPLEXenv, CPLEXModel, CPXPROB_QP);
		} else if (CPXgetprobtype(CPLEXenv, CPLEXModel) == CPXPROB_MILP) {
			Status = CPXchgprobtype(CPLEXenv, CPLEXModel, CPXPROB_MIQP);
		}
		if (Status) {
			FErrorFile() << "Failed to change problem type." << endl;
			FlushErrorFile();
			return FAIL;
		}
		
		for (int i=0; i < NumCols; i++) {
			for (int j=0; j < NumCols; j++) {
				Status = CPXchgqpcoef(CPLEXenv, CPLEXModel, i, j, 0);
				if (Status) {
					FErrorFile() << "Failed to change quadratic coefficient." << endl;
					FlushErrorFile();
					return FAIL;
				}
			}
		}
		for (int i=0; i < int(InEquation->QuadOne.size()); i++) {
			Status = CPXchgqpcoef(CPLEXenv, CPLEXModel, InEquation->QuadOne[i]->Index, InEquation->QuadTwo[i]->Index, InEquation->QuadCoeff[i]);
			if (Status) {
				FErrorFile() << "Failed to change quadratic coefficient." << endl;
				FlushErrorFile();
				return FAIL;
			}
		}
	}	
	
	return SUCCESS;
}
示例#6
0
int CPLEXInitialize() {
	int Status = 0;
	
	//First I open the CPLEX environment if it is not already open
	if (CPLEXenv == NULL) {
		CPLEXenv = CPXopenCPLEX (&Status);
	}
	if (CPLEXenv == NULL || Status) {
		FErrorFile() << "Failed to initialize CPLEX environment. Check license server on aterneus." << endl;
		FlushErrorFile();
		return FAIL;
	}

	//Now I set any environment variables
	Status = CPXsetintparam(CPLEXenv, CPX_PARAM_SCRIND, CPX_ON);
	Status = CPXsetdblparam(CPLEXenv, CPX_PARAM_WORKMEM, 50);
	Status = CPXsetstrparam(CPLEXenv, CPX_PARAM_WORKDIR, FOutputFilepath().data());
	Status = CPXsetintparam(CPLEXenv, CPX_PARAM_NODEFILEIND, 2);
	Status = CPXsetdblparam(CPLEXenv, CPX_PARAM_TRELIM, 50);

	if (Status) {
		FErrorFile() << "Failed to set screen indicators to on." << endl;
		FlushErrorFile();
		return FAIL;
	}

	if (GetParameter("CPLEX solver time limit").length() > 0 && GetParameter("CPLEX solver time limit").compare("none") != 0) { 
		Status = CPXsetdblparam (CPLEXenv, CPX_PARAM_TILIM, atof(GetParameter("CPLEX solver time limit").data()));
		if (Status) {
			FErrorFile() << "Failed to set CPLEX time limit." << endl;
			FlushErrorFile();
			return FAIL;
		}
	}

	//I set the number of processors to run on if allowed to
	
	// SYSTEM_INFO sysinfo;
	// GetSystemInfo( &sysinfo );

	// int numCPU = sysinfo.dwNumberOfProcessors;

	Status = CPXsetintparam(CPLEXenv, CPX_PARAM_THREADS, 1);
	Status = CPXsetintparam(CPLEXenv, CPX_PARAM_PARALLELMODE, 0);
	Status = CPXsetintparam (CPLEXenv, CPX_PARAM_MIPDISPLAY, 0);

	//Next I clear out any models that currently exist
	if (CPLEXClearSolver() != SUCCESS) {
		return FAIL; //error message already printed	
	}

	//Now I create a new CPLEX model
	CPLEXModel = CPXcreateprob (CPLEXenv, &Status, "LPProb");
	Status = CPXchgprobtype(CPLEXenv, CPLEXModel, CPXPROB_LP);
	if (Status || CPLEXModel == NULL) {
		FErrorFile() << "Failed to create new CPLEX model." << endl;
		FlushErrorFile();
		return FAIL;
	}

	return SUCCESS;
}
示例#7
0
OptSolutionData* CPLEXRunSolver(int ProbType) {
	OptSolutionData* NewSolution = NULL;
	int Status = 0;
	if (ProbType == LP) {
		Status = CPXsetintparam (CPLEXenv, CPX_PARAM_LPMETHOD, CPX_ALG_AUTOMATIC);
		if (Status) {
			FErrorFile() << "Failed to set the optimization method." << endl;
			FlushErrorFile();
			return NULL;
		}
		Status = CPXsetintparam (CPLEXenv, CPX_PARAM_SIMDISPLAY, 0);
		if (Status) {
			FErrorFile() << "Failed to set the optimization method." << endl;
			FlushErrorFile();
			return NULL;
		}
		Status = CPXchgprobtype(CPLEXenv, CPLEXModel, CPXPROB_LP);
		Status = CPXlpopt(CPLEXenv, CPLEXModel);
	} else if(ProbType == MILP || ProbType == MIQP) {
		//Setting the bound tightening on high
		Status = CPXsetintparam (CPLEXenv, CPX_PARAM_BNDSTRENIND, 1);
		if (Status) {
			FErrorFile() << "Failed to set the optimization method." << endl;
			FlushErrorFile();
			return NULL;
		}
		//Setting tolerance to 1e-9 instead of 1e-6
		double tolerance = atof(GetParameter("Solver tolerance").data());
		Status = CPXsetdblparam(CPLEXenv,CPX_PARAM_EPRHS, tolerance);
		if (Status) {
			FErrorFile() << "Failed to set the optimization method." << endl;
			FlushErrorFile();
			return NULL;
		}
		Status = CPXsetdblparam(CPLEXenv,CPX_PARAM_EPINT, tolerance);
		if (Status) {
			FErrorFile() << "Failed to set the optimization method." << endl;
			FlushErrorFile();
			return NULL;
		}
		//Deactivates all messages from MIP solver
		Status = CPXchgprobtype(CPLEXenv, CPLEXModel, CPXPROB_MILP);
		Status = CPXmipopt (CPLEXenv, CPLEXModel);
	} else if(ProbType == QP) {
		Status = CPXqpopt (CPLEXenv, CPLEXModel);
	}
	if (Status ) {
		cout << "Failed to optimize LP." << endl;
		return NULL;
	}
	int Temp = CPXgetstat (CPLEXenv, CPLEXModel);
	NewSolution = new OptSolutionData;
	if (Temp == CPX_STAT_UNBOUNDED) {
		cout << "Model is unbounded" << endl;
		FErrorFile() << "Model is unbounded" << endl;
		FlushErrorFile();
		NewSolution->Status = UNBOUNDED;
		return NewSolution;
	} else if (Temp == CPX_STAT_INFEASIBLE) {
		cout << "Model is infeasible" << endl;
		FErrorFile() << "Model is infeasible" << endl;
		FlushErrorFile();
		NewSolution->Status = INFEASIBLE;
		return NewSolution;
	} else if (Temp == CPX_STAT_INForUNBD ) {
		cout << "Model is infeasible or unbounded" << endl;
		FErrorFile() << "Model is infeasible or unbounded" << endl;
		FlushErrorFile();
		NewSolution->Status = INFEASIBLE;
		return NewSolution;
	} else {
		NewSolution->Status = SUCCESS;
	}

	int NumberColumns = CPXgetnumcols (CPLEXenv, CPLEXModel);
	int NumberRows = CPXgetnumrows (CPLEXenv, CPLEXModel);
	NewSolution->NumVariables = NumberColumns;
	NewSolution->SolutionData.resize(NumberColumns);

	double* x = new double[NumberColumns];
	
	if (ProbType == MILP || ProbType == MIQP) {
		Status = CPXgetmipobjval (CPLEXenv, CPLEXModel, &(NewSolution->Objective));
		Status = CPXgetmipx (CPLEXenv, CPLEXModel, x, 0, NumberColumns-1);
	} else {
		Status = CPXsolution(CPLEXenv,CPLEXModel,NULL,&(NewSolution->Objective),x,NULL,NULL,NULL);
	}
	
	if ( Status ) {
		cout << "Failed to obtain objective value." << endl;
		delete [] x;
		NewSolution->Status = INFEASIBLE;
		return NewSolution;
	}

	cout << "Objective value: " << NewSolution->Objective << endl;
	/*
	string* StrNames = new string[NumberColumns];
	char** Names = new char*[NumberColumns];
	char* NameStore = new char[7*NumberColumns];
	int Surplus = 0;

	Status = CPXgetcolname(CPLEXenv, CPLEXModel, Names, NameStore, 7*NumberColumns, &Surplus, 0, NumberColumns-1);
	if (Status) {
		FErrorFile() << "Failed to get column names." << endl;
		FlushErrorFile();
		delete [] StrNames;
		delete [] Names;
		delete [] NameStore;
		delete [] x;
		delete NewSolution;
		return NULL;
	}
	*/
	for (int i=0; i < NumberColumns; i++) {
		//StrNames[i].assign(Names[i]);
		//StrNames[i] = StrNames[i].substr(1, StrNames[i].length()-1);
		//NewSolution->SolutionData[atoi(StrNames[i].data())-1] = x[i];
		NewSolution->SolutionData[i] = x[i];
	}
	/*
	delete [] StrNames;
	delete [] Names;
	delete [] NameStore;
	*/
	delete [] x;

	return NewSolution;
}
示例#8
0
文件: admipex6.c 项目: renvieir/ioc
int
main (int  argc,
      char *argv[])
{
   int status = 0;

   /* Declare and allocate space for the variables and arrays where
      we will store the optimization results, including the status, 
      objective value, and variable values */
   
   int    solstat;
   double objval, relobj;
   double *x = NULL;
	 
   MYCB info;

   CPXENVptr env = NULL;
   CPXLPptr  lp  = NULL;
   CPXLPptr  lpclone = NULL;

   int j;
   int cur_numcols;

   /* Check the command line arguments */

   if ( argc != 2 ) {
      usage (argv[0]);
      goto TERMINATE;
   }

   /* Initialize the CPLEX environment */

   env = CPXopenCPLEX (&status);

   /* If an error occurs, the status value indicates the reason for
      failure.  A call to CPXgeterrorstring will produce the text of
      the error message.  Note that CPXopenCPLEX produces no
      output, so the only way to see the cause of the error is to use
      CPXgeterrorstring.  For other CPLEX routines, the errors will
      be seen if the CPXPARAM_ScreenOutput parameter is set to CPX_ON */

   if ( env == NULL ) {
      char errmsg[CPXMESSAGEBUFSIZE];
      fprintf (stderr, "Could not open CPLEX environment.\n");
      CPXgeterrorstring (env, status, errmsg);
      fprintf (stderr, "%s", errmsg);
      goto TERMINATE;
   }

   /* Turn on output to the screen */

   status = CPXsetintparam (env, CPXPARAM_ScreenOutput, CPX_ON);
   if ( status ) {
      fprintf (stderr, 
               "Failure to turn on screen indicator, error %d.\n",
               status);
      goto TERMINATE;
   }


   /* Turn on traditional search for use with control callbacks */

   status = CPXsetintparam (env, CPXPARAM_MIP_Strategy_Search,
                            CPX_MIPSEARCH_TRADITIONAL);
   if ( status )  goto TERMINATE;

   /* Create the problem, using the filename as the problem name */

   lp = CPXcreateprob (env, &status, argv[1]);

   /* A returned pointer of NULL may mean that not enough memory
      was available or there was some other problem.  In the case of 
      failure, an error message will have been written to the error 
      channel from inside CPLEX.  In this example, the setting of
      the parameter CPXPARAM_ScreenOutput causes the error message to
      appear on stdout.  Note that most CPLEX routines return
      an error code to indicate the reason for failure */

   if ( lp == NULL ) {
      fprintf (stderr, "Failed to create LP.\n");
      goto TERMINATE;
   }

   /* Now read the file, and copy the data into the created lp */

   status = CPXreadcopyprob (env, lp, argv[1], NULL);
   if ( status ) {
      fprintf (stderr,
               "Failed to read and copy the problem data.\n");
      goto TERMINATE;
   }

   /* We transfer a problem with semi-continuous or semi-integer
      variables to a MIP problem by adding variables and  
      constraints. So in MIP callbacks, the size of the problem
      is changed and this example won't work for such problems */

   if ( CPXgetnumsemicont (env, lp) + CPXgetnumsemiint (env, lp) ) {
      fprintf (stderr, 
         "Not for problems with semi-continuous or semi-integer variables.\n");
      goto TERMINATE;
   }

   /* The size of the problem should be obtained by asking CPLEX what
      the actual size is. cur_numcols store the current number 
      of columns */

   cur_numcols = CPXgetnumcols (env, lp);

   x = (double *) malloc (cur_numcols * sizeof (double));
   if ( x == NULL ) {
      fprintf (stderr, "Memory allocation failed.\n");
      goto TERMINATE;
   }

   /* Solve relaxation of MIP */

   /* Clone original model */

   lpclone = CPXcloneprob (env, lp, &status);
   if ( status ) {
      fprintf (stderr, "Failed to clone problem.\n");
      goto TERMINATE;
   }

   /* Relax */

   status = CPXchgprobtype (env, lpclone, CPXPROB_LP);
   if ( status ) {
      fprintf (stderr, "Failed to relax problem.\n");
      goto TERMINATE;
   }

   /* Solve LP relaxation of original model using "default"
      LP solver */

   status = CPXlpopt (env, lpclone);
   if ( status ) {
      fprintf (stderr, "Failed to solve relaxation.\n");
      goto TERMINATE;
   }

   status = CPXsolution (env, lpclone, NULL, &relobj, x, NULL,
                         NULL, NULL);
   if ( status ) {
      fprintf (stderr, "Failed to extract solution.\n");
      goto TERMINATE;
   }

   printf ("Solution status = %d", CPXgetstat(env,lpclone));
   printf ("\nLP relaxation objective: %.4e\n\n", relobj);

   /* Set up solve callback */
   
   info.count = 0;
   info.mip   = lp;
   info.relx  = x;

   status = CPXsetsolvecallbackfunc (env, &solvecallback,
                                     (void *) &info);
   if ( status ) {
      fprintf (stderr, "Failed to set solve callback.\n");
      goto TERMINATE;
   }

   /* Optimize the problem and obtain solution */

   status = CPXmipopt (env, lp);
   if ( status ) {
      fprintf (stderr, "Failed to optimize MIP.\n");
      goto TERMINATE;
   }

   solstat = CPXgetstat (env, lp);

   status = CPXgetobjval (env, lp, &objval);
   if ( status ) {
      fprintf (stderr,"Failed to obtain objective value.\n");
      goto TERMINATE;
   }

   printf ("Solution status %d.\n", solstat); 
   printf ("Objective value %.10g\n", objval);

   status = CPXgetx (env, lp, x, 0, cur_numcols-1);
   if ( status ) {
      fprintf (stderr, "Failed to obtain solution.\n");
      goto TERMINATE;
   }

   /* Write out the solution */

   for (j = 0; j < cur_numcols; j++) {
      if ( fabs (x[j]) > 1e-10 ) {
         printf ( "Column %d:  Value = %17.10g\n", j, x[j]);
      }
   }
   

TERMINATE:

   /* Free the solution vector */

   free_and_null ((char **) &x);

   /* Free the problem as allocated by CPXcreateprob and
      CPXreadcopyprob, if necessary */

   if ( lp != NULL ) {
      status = CPXfreeprob (env, &lp);
      if ( status ) {
         fprintf (stderr, "CPXfreeprob failed, error code %d.\n",
                  status);
      }
   }

   /* Free the cloned lp as allocated by CPXcloneprob,
      if necessary */

   if ( lpclone != NULL ) {
      status = CPXfreeprob (env, &lpclone);
      if ( status ) {
         fprintf (stderr, "CPXfreeprob failed, error code %d.\n",
                  status);
      }
   }

   /* Free the CPLEX environment, if necessary */

   if ( env != NULL ) {
      status = CPXcloseCPLEX (&env);

      /* Note that CPXcloseCPLEX produces no output, so the only 
         way to see the cause of the error is to use
         CPXgeterrorstring.  For other CPLEX routines, the errors 
         will be seen if the CPXPARAM_ScreenOutput parameter is set to 
         CPX_ON */

      if ( status ) {
         char errmsg[CPXMESSAGEBUFSIZE];
         fprintf (stderr, "Could not close CPLEX environment.\n");
         CPXgeterrorstring (env, status, errmsg);
         fprintf (stderr, "%s", errmsg);
      }
   }
     
   return (status);

} /* END main */