function [exitFlag exitMsg netStruct] = fa_minimaxUtilization_xde (netStruct, algorithmParameters, net2planParameters)

	% Algorithm for flow assignment problems which tries to minimize
	% the maximum utilization among all links within the network. It uses a
	% flow-link formulation implemented in CVX
	%
	% This algorithm has no specific parameters.
	%
	% It requires CVX solver installed and running.

	%% Sanity checks
	assert(isfield(netStruct, 'linkTable'), 'A set of links is required');
	assert(isfield(netStruct, 'demandTable'), 'A set of demands is required');
	assert(isCvxInstalledAndRunning(), 'CVX solver must be installed and running');
		
	u_e = netStruct.linkCapacityInErlangs;
	h_d = netStruct.offeredTrafficInErlangs;

	N = size(netStruct.nodeXYPositionTable, 1);
	E = size(netStruct.linkTable, 1);
	D = size(netStruct.demandTable, 1);
	
	% compute the adjacency matrix and the right-hand-side of flow
	% conservation constraints
	A_ne = linkTable2incidenceMatrix(netStruct.linkTable, N);
	w_nd = linkTable2incidenceMatrix(netStruct.demandTable, N);
		
	cvx_begin

		cvx_quiet(true);
		
		variables rho; % rho: utilization of the link with highest utilization
		variables x_de(D, E); % x_de: fraction [0...1] of traffic of d, that traverses link e

		minimize( rho )

		subject to

			% 1. flow conservation constraints 
			% sum(e out n) x_de - sum(e in n) x_de == 1 if n=a(d)
			% sum(e out n) x_de - sum(e in n) x_de == -1 if n=b(d)
			% sum(e out n) x_de - sum(e in n) x_de == 0 otherwise
			% for all demand d, node n
			% a. vectorial form (all constraints in a single line of code)
			A_ne * x_de' == w_nd;
			% b. equivalent expression with for-loops (slower)
%			 for n=1:N
%				 linksOut = find (netStruct.linkTable(:,1) == n);
%				 linksIn = find (netStruct.linkTable(:,2) == n);
%				 for d=1:D
%					 ingressNode = netStruct.demandTable (d,1);
%					 egressNode = netStruct.demandTable (d,2);
%					 if (n == ingressNode)
%						 sum(x_de(d,linksOut)) - sum(x_de(d,linksIn)) == 1;
%					 elseif (n == egressNode)
%						 sum(x_de(d,linksOut)) - sum(x_de(d,linksIn)) == -1;
%					 else
%						 sum(x_de(d,linksOut)) - sum(x_de(d,linksIn)) == 0;
%					 end
%				 end
%			 end
			
			% utilization in a link is <= rho
			% sum(d) h_d x_de <= u_e for all links e
			% a. vectorial form (all constraints in a single line of code)
			h_d * x_de <= rho * u_e;
			% b. equivalent expression with for-loops (slower)
%			 for e=1:E
%				 trafficInTheLink = 0;
%				 for d=1:D
%					 trafficInTheLink = trafficInTheLink + h_d(d) * x_de(d,e);
%				 end
%				 trafficInTheLink <= rho * u_e(e);
%			 end
			
			
			% no link can be overcongested
			rho <= 1;
			
			% non negativity
			x_de >= 0;
			% rho >= 0; % this is redundant, so can be removed
			% x_de <= 1; % this is redundant, so can be removed

	cvx_end
		
	if strcmp(cvx_status, 'Solved') || strcmp(cvx_status, 'Inaccurate/Solved')
			
		exitFlag = 0;
		exitMsg = 'OK!';
			
		% limit numerical errors (something close 0 is 0, close to 1 is 1)
		x_de(x_de > 1-net2planParameters.precisionFactor) = 1;
		x_de(x_de < net2planParameters.precisionFactor) = 0;

		% convert the x_de vector to a x_dp routing
		[x_dp pathList] = xde2xdp(x_de, netStruct.linkTable, ones(1, E), netStruct.demandTable);

		netStruct.routingMatrix = x_dp;
		netStruct.pathList = pathList;

	else

		exitFlag = -1;
		exitMsg = cvx_status;
		netStruct = [];

	end
		

end