function [exitFlag exitMsg netStruct] = ca_minAvNetDelayLinearCost (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 linearle with capacities:
	% C_e = alpha*u_e + beta*d_e*u_e 
	%
	% It requires CVX solver installed and running.
	%
	% PARAM: alpha | 0 | Linear cost coefficient with capacity (cost per Erlang)
	% PARAM: beta | 1 | Linear cost coefficient with capacity-distance power product (cost per 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');

	alpha = str2double(algorithmParameters.alpha);
	beta = str2double(algorithmParameters.beta);
	Cmax = str2double(algorithmParameters.Cmax);
	assert(isfinite(alpha), '"alpha" must be a number');
	assert(isfinite(beta), '"beta" must be a number');
	assert(isfinite(Cmax) && (Cmax > 0), '"Cmax" must be a number greater than 0');
	assert(isCvxInstalledAndRunning(), 'CVX solver must be installed and running');

	% initialize some variables
	E = size(netStruct.linkTable, 1);
	h_d = netStruct.offeredTrafficInErlangs;
	x_dp = netStruct.routingMatrix;
	delta_pe = seqLinksPerPath2linkOccupancyPerPath(netStruct.pathList, E);
	y_e = trafficPerLink(h_d, x_dp, delta_pe);
	distance_e = netStruct.linkLengthInKm;

	cvx_begin

		cvx_quiet(true);

		% NOTE: We prefer rho_e as decision variables since delay function
		% can be expressed easily in a convex form as a function o link
		% utilizations using quad_over_lin
		
		% NOTE: We do not consider the factor L/sum(h_d) in the average
		% delay since it does not affect the result, and can cause
		% numerical errors
		
		variables rho_e(1, E); % utilization in the links

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

			rho_e <= 1;
			rho_e >= 0;
			sum(inv_pos(rho_e) .* y_e .* (alpha + beta * distance_e)) <= Cmax;

	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

