示例#1
0
 void Callback::constructRHS( GraphVariables const & vars
                            , NodeSet        const & dS
                            , NodeSet        const & S
                            , IloExpr              & rhs
                            ) const {
   rhs.clear();

   for ( Graph::Node const & j : dS ) {
     rhs += vars.xVars[vars.nodeToIndex[j]];
   }

   for ( Graph::Node const & j : S ) {
     rhs += vars.yVars[vars.nodeToIndex[j]];
   }
 }
示例#2
0
int CProblem::setModel() {
	//time_t start, end;

	numvar = 1+n; // lambda + all c;

	IloEnv  env;
	try {
		IloModel model(env);
		IloCplex cplex(env);

		/*Variables*/
		IloNumVar lambda(env, "lambda");
		IloNumVarArray c(env, n);//
		for (unsigned int u=0; u<n; u++) {
			std::stringstream ss;
			ss << u;
			std::string str = "c" + ss.str();
			c[u]=IloNumVar(env, str.c_str());
		}

		IloArray<IloIntVarArray> z(env,n);
		for (unsigned int u=0; u<n; u++) {
			z[u]= IloIntVarArray(env, n);
			for (unsigned int v=0; v<n; v++) {
				std::stringstream ss;
				ss << u;
				ss << v;
				std::string str = "z" + ss.str();
				z[u][v] = IloIntVar(env, 0, 1, str.c_str());
			}
		}

		/* Constant M*/
		
		int M=n*max_d;
		UB = M;

		/*  Objective*/
		model.add(IloMinimize(env, lambda));
		//model.add(IloMinimize(env, IloSum(c)));
		/*Constrains*/
		model.add(lambda - UB <= 0);

		/* d=function of the distance */
		IloArray<IloNumArray> Par_d(env,n);
		for (unsigned int u=0; u<n; u++) {
			Par_d[u]=IloNumArray(env,n);
			for (unsigned int v=0; v<n; v++) {
				Par_d[u][v]=d[u][v];
			}
		}

		for (unsigned u=0; u<n; u++) {
			for (unsigned v=0; v<u; v++) {
				model.add(c[v]-c[u]+M*   z[u][v]  >= Par_d[u][v] );
				model.add(c[u]-c[v]+M*(1-z[u][v]) >= Par_d[u][v]);
				numvar++; // + z[u][v]
			}
		}

/*
			for (unsigned i=0; i<sqrt(n)-1; i=i+1) {
				for (unsigned j=0; j<sqrt(n)-1; j=j+1) {
				    //square lattice
				    model.add (c[i*sqrt(n)+j]     +c[i*sqrt(n)+j+1] +
					       c[(i+1)*sqrt(n)+j] +c[(i+1)*sqrt(n)+j+1]>= 16-4*sqrt(2));  // Bedingung fuer Quadratischen Gridgraph und d(x) = 3-x
//					
					// triangular lattice
//					model.add (c[i*5+j]+c[i*5+j+1] +
//					           c[(i+1)+j] >= 4);  // Bedingung fuer Quadratischen Gridgraph und d(x) = 3-x
//					model.add (c[i*sqrt(n)+j]+c[i*sqrt(n)+j+1] +
//					           c[(i+1)*sqrt(n)+j]+c[(i+1)*sqrt(n)+j+1] >= 22 - 4*sqrt(2));  // Bedingung fuer Quadratischen Gridgraph und d(x) = 4-x

				}
			}
*/

/*
			for (unsigned i=0; i<sqrt(n)-2; i+=3) {
				for (unsigned j=0; j<sqrt(n)-2; j+=3) {
//					model.add (c[i*sqrt(n)+j]    + c[i*sqrt(n)+j+1]    + c[i*sqrt(n)+j+2] +
//					           c[(i+1)*sqrt(n)+j]+ c[(i+1)*sqrt(n)+j+1]+ c[(i+1)*sqrt(n)+j+2] +
//					           c[(i+2)*sqrt(n)+j]+ c[(i+2)*sqrt(n)+j+1]+ c[(i+2)*sqrt(n)+j+2]
//					           >= 60-17*sqrt(2)-3*sqrt(5));  // Bedingung fuer Quadratischen Gridgraph und d(x) = 3-x
//					model.add (c[i*sqrt(n)+j]    + c[i*sqrt(n)+j+1]    + c[i*sqrt(n)+j+2] +
//					           c[(i+1)*sqrt(n)+j]+ c[(i+1)*sqrt(n)+j+1]+ c[(i+1)*sqrt(n)+j+2] +
//					           c[(i+2)*sqrt(n)+j]+ c[(i+2)*sqrt(n)+j+1]+ c[(i+2)*sqrt(n)+j+2]
//					           >= 82-8*sqrt(2)-2*sqrt(5));  // Bedingung fuer Quadratischen Gridgraph und d(x) = 4-x
				}
			}

*/
		for (unsigned int v=0; v<n; v++) {
			IloExpr expr;
			model.add (c[v] <= lambda);
			model.add (c[v] >= 0);
			expr.end();
		}



		std::cout << "Number of variables " << numvar << "\n";

		/* solve the Model*/
		cplex.extract(model);
		cplex.exportModel("L-Labeling.lp");

		/*
		start = clock();
		int solveError = cplex.solve();
		end = clock ();
		*/

		IloTimer timer(env);
		timer.start();
		int solveError = cplex.solve();
		timer.stop();

		if ( !solveError ) {
			std::cout << "STATUS : "<< cplex.getStatus() << "\n";
			env.error() << "Failed to optimize LP \n";
			exit(1);
		}
		//Info.time = (double)(end-start)/(double)CLOCKS_PER_SEC;
		Info.time = timer.getTime();

		std::cout << "STATUS : "<< cplex.getStatus() << "\n";
		/* get the solution*/
		env.out() << "Solution status = " << cplex.getStatus() << "\n";
		numconst = cplex.getNrows();
		env.out() << " Number of constraints = " << numconst << "\n";
		lambda_G_d=cplex.getObjValue();
		env.out() << "Solution value  = " << lambda_G_d << "\n";
		for (unsigned int u=0; u<n; u++) {
			C.push_back(cplex.getValue(c[u]));
			std::cout << "c(" << u << ")=" << C[u]<< " ";
		}
		std::cout <<"\n";
		/*
		for (unsigned int u=0; u<n; u++) {
			for (unsigned int v=0; v<u; v++) {
				std::cout<< "z[" << u <<"][" << v << "]="<< cplex.getValue( z[u][v]) << " ";
				Z.push_back(cplex.getValue( z[u][v]));
			}
			std::cout << "\n";
		}
		std::cout <<"\n";
		 */
	}	// end try
	catch (IloException& e) {
		std::cerr << "Concert exception caught: " << e << std::endl;
	}
	catch (...) {
		std::cerr << "Unknown exception caught" << std::endl;
	}
	env.end();
	return 0;
}
示例#3
0
// This routine separates Benders' cuts violated by the current x solution.
// Violated cuts are found by solving the worker LP
//
IloBool
separate(const Arcs x, const IloNumArray2 xSol, IloCplex cplex,
         const IloNumVarArray v, const IloNumVarArray u,
         IloObjective obj, IloExpr cutLhs, IloNum& cutRhs)
{
   IloBool violatedCutFound = IloFalse;

   IloEnv env = cplex.getEnv();
   IloModel mod = cplex.getModel();

   IloInt numNodes = xSol.getSize();
   IloInt numArcs  = numNodes * numNodes;
   IloInt i, j, k, h;

   // Update the objective function in the worker LP:
   // minimize sum(k in V0) sum((i,j) in A) x(i,j) * v(k,i,j)
   //          - sum(k in V0) u(k,0) + sum(k in V0) u(k,k)
   
   mod.remove(obj);
   IloExpr objExpr = obj.getExpr();
   objExpr.clear();
   for (k = 1; k < numNodes; ++k) {
      for (i = 0; i < numNodes; ++i) {
         for (j = 0; j < numNodes; ++j) {
               objExpr +=  xSol[i][j] * v[(k-1)*numArcs + i*numNodes + j];
         }
      }
   }
   for (k = 1; k < numNodes; ++k) {
      objExpr += u[(k-1)*numNodes + k];
      objExpr -= u[(k-1)*numNodes];
   }
   obj.setExpr(objExpr);
   mod.add(obj);
   objExpr.end(); 

   // Solve the worker LP

   cplex.solve();

   // A violated cut is available iff the solution status is Unbounded

   if ( cplex.getStatus() == IloAlgorithm::Unbounded ) {

      IloInt vNumVars = (numNodes-1) * numArcs;
      IloNumVarArray var(env);
      IloNumArray val(env);

      // Get the violated cut as an unbounded ray of the worker LP

      cplex.getRay(val, var);

      // Compute the cut from the unbounded ray. The cut is:
      // sum((i,j) in A) (sum(k in V0) v(k,i,j)) * x(i,j) >=
      // sum(k in V0) u(k,0) - u(k,k)

      cutLhs.clear();
      cutRhs = 0.;

      for (h = 0; h < val.getSize(); ++h) {

         IloInt *index_p = (IloInt*) var[h].getObject();
         IloInt index = *index_p;

         if ( index >= vNumVars ) {
            index -= vNumVars;
            k = index / numNodes + 1;
            i = index - (k-1)*numNodes;
            if ( i == 0 )
               cutRhs += val[h];
            else if ( i == k )
               cutRhs -= val[h];
         }
         else {
            k = index / numArcs + 1;
            i = (index - (k-1)*numArcs) / numNodes;
            j = index - (k-1)*numArcs - i*numNodes;
            cutLhs += val[h] * x[i][j];
         }
      }

      var.end();
      val.end();

      violatedCutFound = IloTrue;
   }

   return violatedCutFound;

} // END separate
示例#4
0
/** Separation function.
 * This function is invoked whenever CPLEX finds an integer feasible
 * solution. It then separates either feasibility or optimality cuts
 * on this solution.
 */
void BendersOpt::LazyConstraintCallback::main() {
   std::cout << "Callback invoked. Separate Benders cuts." << std::endl;

   IloNumArray x(getEnv());
   IloNumArray rayVals(getEnv());
   IloNumVarArray rayVars(getEnv());
   IloNumArray cutVal(getEnv());
   IloNumVarArray cutVar(getEnv());

   getValues(x, master->vars);

   bool error = false;

   // Iterate over blocks and trigger a separation on each of them.
   // The separation is triggered asynchronously so that it can happen
   // on different remote objects simultaneously.
   for (BlockVector::size_type b = 0; b < blocks.size(); ++b) {
      Block *const block = blocks[b];

      // Remove current objective from the block's model.
      IloModel model = block->cplex.getModel();
      IloObjective obj = block->obj;
      model.remove(obj);
      IloExpr newObj = obj.getExpr();
         
      // Iterate over the fixed master variables in this block to update
      // the block's objective function.
      // Each fixed variable goes to the right-hand side and therefore
      // into the objective function.
      for (std::vector<Block::FixData>::const_iterator it = block->fixed.begin(); it != block->fixed.end(); ++it)
         newObj -= block->vars[it->row] * (it->val * x[it->col]);
      obj.setExpr(newObj);
      model.add(obj);
      newObj.end();

      // If the problem is unbounded we need to get an infinite ray in
      // order to be able to generate the respective Benders cut. If
      // CPLEX proves unboundedness in presolve then it will return
      // CPX_STAT_INForUNBD and no ray will be available. So we need to
      // disable presolve.
      block->cplex.setParam(IloCplex::Param::Preprocessing::Presolve, false);
      block->cplex.setParam(IloCplex::Param::Preprocessing::Reduce, 0);

      // Solve the updated problem to optimality.
      block->cplex.setParam(IloCplex::Param::RootAlgorithm, IloCplex::Primal);
      try {
         handles[b] = block->cplex.solve(true);
      } catch (...) {
         // If there is an exception then we need to kill and join
         // all remaining solves. Otherwise we may leak handles.
         while (--b > 0) {
            handles[b].kill();
            handles[b].join();
         }
         throw;
      }
   }

   // Wait for the various LP solves to complete.
   for (BlockVector::size_type b = 0; b < blocks.size(); ++b)
      handles[b].join();

   // See if we need to generate cuts.
   for (BlockVector::size_type b = 0; b < blocks.size(); ++b) {
      Block *const block = blocks[b];
      cutVal.clear();
      cutVar.clear();
      double cutlb = -IloInfinity;
      double cutub = IloInfinity;

      // We ust STL types here since they are exception safe.
      std::vector<double> tmp(master->vars.getSize(), 0);
      std::map<IloNumVar,double,ExtractableLess<IloNumVar> > rayMap;

      // Depending on the status either seperate a feasibility or an
      // optimality cut.
      switch (block->cplex.getStatus()) {
      case IloAlgorithm::Unbounded:
         {
            // The subproblem is unbounded. We need to extract a feasibility
            // cut from an unbounded ray of the problem (see also the comments
            // at the top of this file).
            std::cout << "unbounded ";
            block->cplex.getRay(rayVals, rayVars);
            cutub = 0.0;
            for (IloInt j = 0; j < rayVars.getSize(); ++j) {
               cutub -= rayVals[j] * block->objMap[rayVars[j]];
               rayMap[rayVars[j]] = rayVals[j];
            }
            for (std::vector<Block::FixData>::const_iterator it = block->fixed.begin(); it != block->fixed.end(); ++it)
               tmp[it->col] -= it->val * rayMap[block->vars[it->row]];
            for (IloInt j = 0; j < master->vars.getSize(); ++j) {
               if ( fabs (tmp[j]) > 1e-6 ) {
                  cutVar.add(master->vars[j]);
                  cutVal.add(tmp[j]);
               }
            }
         }
         break;
      case IloAlgorithm::Optimal:
         {
            // The subproblem has a finite optimal solution.
            // We need to check if this gives rise to an optimality cut (see
            // also the comments at the top of this file).            
            std::cout << "optimal ";
            double const objval = block->cplex.getObjValue();
            double const eta = x[etaind + b];
            block->cplex.getValues(block->vars, rayVals);
            
            if ( objval > eta + 1e-6 ) {
               cutub = 0.0;
               for (IloInt j = 0; j < block->vars.getSize(); ++j)
                  cutub -= rayVals[j] * block->objMap[block->vars[j]];
               for (std::vector<Block::FixData>::const_iterator it = block->fixed.begin(); it != block->fixed.end(); ++it)
                  tmp[it->col] -= it->val * rayVals[it->row];
               for (IloInt j = 0; j < master->vars.getSize(); ++j) {
                  if ( fabs (tmp[j]) > 1e-6 ) {
                     cutVal.add(tmp[j]);
                     cutVar.add(master->vars[j]);
                  }
               }
               cutVal.add(-1.0);
               cutVar.add(master->vars[etaind + b]);
            }
         }
         break;
      default:
         std::cerr << "Unexpected status " << block->cplex.getStatus()
                   << std::endl;
         error = true;
         break;
      }
      
      // If a cut was found then add that.
      if ( cutVar.getSize() > 0 ) {
         IloExpr expr(master->env);
         for (IloInt i = 0; i < cutVar.getSize(); ++i)
            expr += cutVar[i] * cutVal[i];
         IloRange cut(getEnv(), cutlb, expr, cutub);
         expr.end();
         std::cout << "cut found: " << cut << std::endl;
         add(cut).end();
      }
      else
         std::cout << "no cuts." << std::endl;
   }
   cutVar.end();
   cutVal.end();
   rayVars.end();
   rayVals.end();
   x.end();
   if ( error )
      throw -1;
}
示例#5
0
int CProblem::setModel() {
	//time_t start, end;

	numvar = 1+n; // lambda + all c;

	IloEnv  env;
	try {
		IloModel model(env);
		IloCplex cplex(env);

		/*Variables*/
		IloNumVar lambda(env, "lambda");
		IloNumVarArray c(env, n);//
		for (unsigned int u=0; u<n; u++) {
			std::stringstream ss;
			ss << u;
			std::string str = "c" + ss.str();
			c[u]=IloNumVar(env, str.c_str());
		}

		IloArray<IloIntVarArray> z(env,n);
		for (unsigned int u=0; u<n; u++) {
			z[u]= IloIntVarArray(env, n);
			for (unsigned int v=0; v<n; v++) {
				std::stringstream ss;
				ss << u;
				ss << v;
				std::string str = "z" + ss.str();
				z[u][v] = IloIntVar(env, 0, 1, str.c_str());
			}
		}

		/* Constant M*/
		int M=n*max_d;
		UB = M;

		/*  Objective*/
		model.add(IloMinimize(env, lambda));

		/*Constrains*/
		model.add(lambda - UB <= 0);

		/* d=function of the distance */
		IloArray<IloNumArray> Par_d(env,n);
		for (unsigned int u=0; u<n; u++) {
			Par_d[u]=IloNumArray(env,n);
			for (unsigned int v=0; v<n; v++) {
				Par_d[u][v]=d[u][v];
			}
		}

		for (unsigned u=0; u<n; u++) {
			for (unsigned v=0; v<u; v++) {
				model.add(c[v]-c[u]+M*   z[u][v]  >= Par_d[u][v] );
				model.add(c[u]-c[v]+M*(1-z[u][v]) >= Par_d[u][v]);
				numvar++; // + z[u][v]
			}
		}


		for (unsigned int v=0; v<n; v++) {
			IloExpr expr;
			model.add (c[v] <= lambda);
			model.add (c[v] >= 0);
			expr.end();
		}



		std::cout << "Number of variables " << numvar << "\n";

		/* solve the Model*/
		cplex.extract(model);
		cplex.exportModel("L-Labeling.lp");

		/*
		start = clock();
		int solveError = cplex.solve();
		end = clock ();
		*/

//		cplex.setParam(IloCplex::Threads, 1);
		cplex.setParam(IloCplex::ClockType , 1 ); // CPU time
	      
		IloTimer timer(env);
		const double startt =  cplex.getTime();
		timer.start();
		int solveError = cplex.solve();
		timer.stop();
		const double stopt = cplex.getTime() - startt;

		if ( !solveError ) {
			std::cout << "STATUS : "<< cplex.getStatus() << "\n";
			env.error() << "Failed to optimize LP \n";
			exit(1);
		}
		//Info.time = (double)(end-start)/(double)CLOCKS_PER_SEC;
		Info.time = timer.getTime();

		std::cout << "STATUS : "<< cplex.getStatus() << "\n";
		/* get the solution*/
		env.out() << "Solution status = " << cplex.getStatus() << "\n";
		env.out() << "Time cplex.getTime " << stopt << "\n";
		numconst = cplex.getNrows();
		env.out() << " Number of constraints = " << numconst << "\n";
		lambda_G_d=cplex.getObjValue();
		env.out() << "Solution value  = " << lambda_G_d << "\n";
		for (unsigned int u=0; u<n; u++) {
			C.push_back(cplex.getValue(c[u]));
			std::cout << "c(" << u << ")=" << C[u]<< " ";
		}
		std::cout <<"\n";
		/*
		for (unsigned int u=0; u<n; u++) {
			for (unsigned int v=0; v<u; v++) {
				std::cout<< "z[" << u <<"][" << v << "]="<< cplex.getValue( z[u][v]) << " ";
				Z.push_back(cplex.getValue( z[u][v]));
			}
			std::cout << "\n";
		}
		std::cout <<"\n";
		 */
	}	// end try
	catch (IloException& e) {
		std::cerr << "Concert exception caught: " << e << std::endl;
	}
	catch (...) {
		std::cerr << "Unknown exception caught" << std::endl;
	}
	env.end();
	return 0;
}
示例#6
0
int CProblem::setModel() {
	//time_t start, end;

	numvar = 1+n; // lambda + all c;

	IloEnv  env;
	try {
		IloModel model(env);
		IloCplex cplex(env);

		/*Variables*/
		IloNumVar lambda(env, "lambda");
		IloNumVarArray c(env, n);//
		for (unsigned int u=0; u<n; u++) {
			std::stringstream ss;
			ss << u;
			std::string str = "c" + ss.str();
			c[u]=IloNumVar(env, str.c_str());
		}

		IloArray<IloIntVarArray> z(env,n);
		for (unsigned int u=0; u<n; u++) {
			z[u]= IloIntVarArray(env, n);
			for (unsigned int v=0; v<n; v++) {
				std::stringstream ss;
				ss << u;
				ss << v;
				std::string str = "z" + ss.str();
				z[u][v] = IloIntVar(env, 0, 1, str.c_str());
			}
		}

		/* Constant M*/
		int UB, LB;
		switch (lattice){
		  case 1: // hexagonal_lattice 
		    if (max_d==3) {LB = 5; UB = 10;}	//d(x) = 3 -x
		    else {LB = 9; UB = 27;}
		    
		    break;
		  case 2:// triangular_lattice
		    if (max_d==3) { LB = 8; UB = 16;}	//d(x) = 3 -x
		    else {LB = 18; UB = 54;}
		    break;
		  case 3:// square_lattice
		    if (max_d==3) { LB = 6; UB = 12;}	//d(x) = 3 -x
		    else { LB = 11; UB = 33;}
		    break;
		  default: UB=n*max_d;break;
		}
		std::cout << "Lattice " << lattice << "\n";
		std::cout << "UB for lambda " << UB << "\n";

		/*  Objective*/
		model.add(IloMinimize(env, lambda));

		/*Constrains*/
		model.add(lambda - UB <= 0);
		model.add(lambda - LB >= 0);
		
		/* d=function of the distance */
		IloArray<IloNumArray> Par_d(env,n);
		for (unsigned int u=0; u<n; u++) {
			Par_d[u]=IloNumArray(env,n);
			for (unsigned int v=0; v<n; v++) {
				Par_d[u][v]=d[u][v];
			}
		}
		
		int M = INT_MAX;//Par_d[0][0] + UB;
		for (unsigned u=0; u<n; u++) {
			for (unsigned v=0; v<u; v++) {
				model.add(c[v]-c[u]+M*   z[u][v]  >= Par_d[u][v] );
				model.add(c[u]-c[v]+M*(1-z[u][v]) >= Par_d[u][v]);
				numvar++; // + z[u][v]
			}
		}

		for (unsigned int v=0; v<n; v++) {
			IloExpr expr;
			model.add (c[v] <= lambda);
			model.add (c[v] >= 0);
			expr.end();
		}



		std::cout << "Number of variables " << numvar << "\n";

		/* solve the Model*/
		cplex.extract(model);
		cplex.exportModel("L-Labeling.lp");

		IloTimer timer(env);
		timer.start();
		int solveError = cplex.solve();
		timer.stop();

		if ( !solveError ) {
			std::cout << "STATUS : "<< cplex.getStatus() << "\n";
			env.error() << "Failed to optimize LP \n";
			exit(1);
		}
		//Info.time = (double)(end-start)/(double)CLOCKS_PER_SEC;
		Info.time = timer.getTime();

		std::cout << "STATUS : "<< cplex.getStatus() << "\n";
		/* get the solution*/
		env.out() << "Solution status = " << cplex.getStatus() << "\n";
		numconst = cplex.getNrows();
		env.out() << " Number of constraints = " << numconst << "\n";
		lambda_G_d=cplex.getObjValue();
		env.out() << "Solution value  = " << lambda_G_d << "\n";
		for (unsigned int u=0; u<n; u++) {
			C.push_back(cplex.getValue(c[u]));
			std::cout << "c(" << u << ")=" << C[u]<< " ";
		}
		std::cout <<"\n";
		/*
		for (unsigned int u=0; u<n; u++) {
			for (unsigned int v=0; v<u; v++) {
				std::cout<< "z[" << u <<"][" << v << "]="<< cplex.getValue( z[u][v]) << " ";
				Z.push_back(cplex.getValue( z[u][v]));
			}
			std::cout << "\n";
		}
		std::cout <<"\n";
		 */
	}	// end try
	catch (IloException& e) {
		std::cerr << "Concert exception caught: " << e << std::endl;
	}
	catch (...) {
		std::cerr << "Unknown exception caught" << std::endl;
	}
	env.end();
	return 0;
}
示例#7
0
int
main(int argc, char **argv)
{
   IloEnv env;
   try {
      IloInt i, j;

      IloNumArray capacity(env), fixedCost(env);
      FloatMatrix cost(env);
      IloInt      nbLocations;
      IloInt      nbClients;

      const char* filename  = "../../../examples/data/facility.dat";
      if (argc > 1) 
         filename = argv[1];
      ifstream file(filename);
      if (!file) {
         cerr << "ERROR: could not open file '" << filename
              << "' for reading" << endl;
         cerr << "usage:   " << argv[0] << " <file>" << endl;
         throw(-1);
      }

      file >> capacity >> fixedCost >> cost;
      nbLocations = capacity.getSize();
      nbClients   = cost.getSize(); 

      IloBool consistentData = (fixedCost.getSize() == nbLocations);
      for(i = 0; consistentData && (i < nbClients); i++)
         consistentData = (cost[i].getSize() == nbLocations);
      if (!consistentData) {
         cerr << "ERROR: data file '" 
              << filename << "' contains inconsistent data" << endl;
         throw(-1);
      }

      IloNumVarArray open(env, nbLocations, 0, 1, ILOINT);
      NumVarMatrix supply(env, nbClients);
      for(i = 0; i < nbClients; i++)
         supply[i] = IloNumVarArray(env, nbLocations, 0, 1, ILOINT);

      IloModel model(env);
      for(i = 0; i < nbClients; i++)
         model.add(IloSum(supply[i]) == 1);
      for(j = 0; j < nbLocations; j++) {
         IloExpr v(env);
         for(i = 0; i < nbClients; i++)
            v += supply[i][j];
         model.add(v <= capacity[j] * open[j]);
         v.end();
      }

      IloExpr obj = IloScalProd(fixedCost, open);
      for(i = 0; i < nbClients; i++) {
         obj += IloScalProd(cost[i], supply[i]);
      }
      model.add(IloMinimize(env, obj));
      obj.end();

      IloCplex cplex(env);
      cplex.extract(model);
      cplex.solve();
	
      cplex.out() << "Solution status: " << cplex.getStatus() << endl;

      IloNum tolerance = cplex.getParam(
         IloCplex::Param::MIP::Tolerances::Integrality);
      cplex.out() << "Optimal value: " << cplex.getObjValue() << endl;
      for(j = 0; j < nbLocations; j++) {
         if (cplex.getValue(open[j]) >= 1 - tolerance) {
            cplex.out() << "Facility " << j << " is open, it serves clients ";
            for(i = 0; i < nbClients; i++) {
               if (cplex.getValue(supply[i][j]) >= 1 - tolerance)
                  cplex.out() << i << " ";
            }
            cplex.out() << endl; 
         }
      }
   }
   catch(IloException& e) {
      cerr  << " ERROR: " << e << endl;   
   }
   catch(...) {
      cerr  << " ERROR" << endl;   
   }
   env.end();
   return 0;
}