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

	% Algorithm for capacity assignment problems which tries to minimize
	% average network delay in the whole network, considering queusing (MM1) and
	% transmission delay. Propagation delay is not considered since it is
	% not affected by the capacities in the links
	% 
	% Average delay is given by:
	% (L/sum_d h_d) \sum_e rho_e / (1-rho_e)
	% Where:
	% h_d: traffic offered by demand d in bps
	% L: average packet length in bits (from net2planParameters)
	%
	% The network cost C is the sum of the costs of the links C_e, where
	% the cost in a link grows in a concave form respect to capacities:
	% C_e = (alpha + d_e * beta ) sqrt(u_e)
	%
	% It requires CVX solver installed and running.
	%
	% PARAM: alpha | 1 | Cost coefficient with sqrt of capacity (cost per sqrt(Erlang))
	% PARAM: beta | 0.01 | Cost coefficient with sqrt of capacity (cost per sqrt(Erlang) and km)
	% PARAM: Cmax | 10000 | Maximum network cost 

	%% Sanity checks
	alpha = str2double (algorithmParameters.alpha);
	beta = str2double (algorithmParameters.beta);
	Cmax = str2double (algorithmParameters.Cmax);
	assert(isfinite(alpha) && alpha >= 0, '"alpha" must be greater or equal than zero');
	assert(isfinite(beta) && beta >= 0, '"beta" must be greater or equal than zero');
	assert(isfinite(Cmax) && Cmax > 0, '"Cmax" must be greater than zero');
	
	assert(isfield(netStruct, 'linkTable'), 'A set of links is required');
	assert(isfield(netStruct, 'demandTable'), 'A set of demands is required');
	assert(isfield(netStruct, 'routingMatrix'), 'A valid routing is required');
	assert(isCvxInstalledAndRunning(), 'CVX solver must be installed and running');
		
	% Take the input parameters
	
	% Initialize some inputs
	E = size(netStruct.linkTable,1);
	delta_pe = seqLinksPerPath2linkOccupancyPerPath (netStruct.pathList, E);
	y_e = trafficPerLink(netStruct.offeredTrafficInErlangs , netStruct.routingMatrix , delta_pe);
	d_e = netStruct.linkLengthInKm;

	cvx_begin
		
		cvx_quiet(true);

		variables rho_e(1,E); 

		minimize( sum(quad_over_lin(rho_e , rho_e - rho_e.^2, 0))  )
			
			subject to

				% cost constraint
				% 1. cost calculated in a single line of code 
				sum ((alpha + d_e * beta ) .* sqrt(y_e) .* inv_pos(sqrt(rho_e))) <= Cmax;
				% 2. we can use a for loop to set the constraint (slower)
%				 C = 0;
%				 for e=1:E
%					 C = C + (alpha + beta * d_e(e)) * sqrt(y_e(e)) * inv_pos (sqrt (rho_e(e)));
%				 end
%				 C <= Cmax;
				
				% non-negativity and minimum capacity constraints
				rho_e >= 0;
				rho_e <= 1;
				
	cvx_end
	   
	if strcmp(cvx_status, 'Solved') || strcmp(cvx_status, 'Inaccurate/Solved')

		exitFlag = 0;
		exitMsg = 'OK!';

		netStruct.linkCapacityInErlangs = y_e ./ rho_e;

	else

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

	end
		
end