classdef Constraints
	%CONSTRAINTS This class represents constraints
	
	properties (SetAccess='private', GetAccess='public')
		maxAverageRT % maximum average response time per class
		maxPercentileRT % percentile values
		maxPercentileValueRT % maximum response time associated to percentile values per class
	end
	
	methods (Access='public')
		function this = Constraints(maxAverageRT, maxPercentileRT, maxPercentileValueRT)
			% Create a CONSTRAINTS object
			% Input parameters:
			% maxAverageRT Maximum average response time per class (1xK)
			% maxPercentileRT Percentiles to be considered (Px1)
			% maxPercentileValueRT Value of the response time in the given
			% percentile per class (PxK)
			
			this.maxAverageRT = maxAverageRT;
			this.maxPercentileRT = maxPercentileRT;
			this.maxPercentileValueRT = maxPercentileValueRT;
		end
		
		function res = value(this)
			% VALUE: Get a value of these constraints in absolute terms.
			% res: value of these constraints in absolute terms
			[x, k] = size(this.maxPercentileValueRT);
			res(x, 1:k) = 0;
			
			% Average response time
			if ~isempty(this.maxAverageRT)
				res(1+end, :) = this.maxAverageRT;
			end
			
			% Percentiles
			if ~isempty(this.maxPercentileRT)

				% Check percentiles for each class

				for ii=1:k
					res(1:x,ii) = this.maxPercentileValueRT(:,ii);
				end				
			end
		end
		
		function res = distance(this, averageRT, percentileRT, percentileValueRT)
			% DISTANCE: Verify constraints and gives a distance (if positive)
			% Input parameters
			% averageRT: actual response time
			% percentileRT/percentileValueRT: actual response time distribution
			% Output parameters
			% res: gives a distance from the target response time for each class. Negative value
			% mean that the constraints are satisfied, positive value that the
			% constraints are not satisfied. (1+PxK)
			
			[x, k] = size(this.maxPercentileValueRT);
			res(x, 1:k) = 0; 
			
			% Calculate the distance from the maximum average response time
			if ~isempty(this.maxAverageRT)
				res(1+end, :) = averageRT - this.maxAverageRT;
			end
 
			% Check the percentiles
			if ~isempty(this.maxPercentileRT)
				
				% Check if we have enough percentile information
				if max(this.maxPercentileRT) > max(percentileRT)+eps
					error(['Not enough information found for percentile ' num2str(max(this.maxPercentileRT))]);
				end

				% Check percentiles for each class
				transformedPercentileValueRT = zeros(x, k);
				for ii=1:x
					indexes = find(this.maxPercentileRT(ii)<=percentileRT+eps);
					transformedPercentileValueRT(ii,:) = percentileValueRT(indexes(1),:);
				end

				for ii=1:k
					res(1:x,ii) = transformedPercentileValueRT(:,ii) - this.maxPercentileValueRT(:,ii);
				end
				
			end
		end
		
		function res = verify(this, averageRT, percentileRT, percentileValueRT)
			% VERIFY: Verify constraints on all nodes and all classes
			% Input parameters
			% averageRT: actual response time
			% percentileRT/percentileValueRT: actual response time distribution
			% Output parameters
			% res: true if the target response time is met for each class
			res = all(all(this.distance(averageRT, percentileRT, percentileValueRT) <= 0.1));
		end
		
		function res = verifyClasses(this, averageRT, percentileRT, percentileValueRT)
			% VERIFYCLASSES: Verify constraints for each class
			% Input parameters
			% averageRT: actual response time
			% percentileRT/percentileValueRT: actual response time distribution
			% Output parameters
			% res: array of booleans, size equal to the number of classes, 
			%		true if the target response time is met for such class
			res = all(this.distance(averageRT, percentileRT, percentileValueRT) <= 0.1);
		end
	end
end


