function m=add_rules(m,n,model_code)
%ADD_RULES adds specified number of rules
%    
%    This function is used to  specify the number and shape of
%    the rules associated to the TS model. 
%    
%    ADD_RULES(M,N)	 add N rules to the model M. When rules
%    are added the OPTIMPARAMS property of the model is set to
%    contain the parameters of the newly added rules. This
%    allow to optimise by default every parameters of a TS
%    system.
%    
%    ADD_RULES(M,N,MODEL_CODE)   add N rules to the model M,
%    MODEL_CODE is  a cell array {x y z}. x is the type of TS
%    model ('crossproduct' or  'projected'). For
%    'crossproduct' models, y is the type of the membership
%    functions  ('gaussian', 'inversedist': 
%    <math>\frac{1}{distance of
%    mahalanobis^{\frac{1}{m-1}}}<alt>1/dist_mahal^(1/(m-1)))<
%    /math>	and z is the type of the consequents  ('linear').
%    For 'projected' systems, y specify the way rules are
%    initially positioned  ('standard': no positionment,
%    'rulegrid': rules evenly disposed on a grid defined by
%    the fuzzy sets)  and z is the type of the consequents 
%    ('linear'). Only rules of the same type can co-exist in a
%    TS model.
%    
%    

%MAN_PAGE_BEGIN
%
%   @purpose  adds specified number of rules. This function is used to 
%   specify the number and shape of the rules associated to the
%   TS model. 
%
%   @synopsis add_rules(m,n)  
%   @description add <code>n</code> rules to the model <code>m</code>.
%	When rules are added the <CODE>optimparams</CODE> property of the model is set to
%	contain the parameters of the newly added rules. This allow to optimise by default
%	every parameters of a TS system.
%
%   @synopsis add_rules(m,n,model_code)  
%   @description  add <CODE>n</CODE> rules to the model <CODE>m</CODE>, <CODE>model_code</CODE> is 
%   a cell array {x y z}. x is the type of TS model ('crossproduct' or 'projected').
%	For 'crossproduct' models, y is the type of the membership functions 
%	('gaussian', 'ungaussian', 'inversedist', 'uninversedist':
%	<math>\frac{1}{distance of mahalanobis^{\frac{1}{m-1}}}<alt>1/dist_mahal^(1/(m-1)))</math>) and z is the type of the consequents 
%   ('linear'). For 'projected' systems, y specify the way rules are initially positioned  ('standard': no positionment, 'rulegrid': rules evenly disposed on a grid defined by the fuzzy sets)  and z is the type of the consequents 
%   ('linear'). Only rules of the same type can co-exist in a TS model.
%
%MAN_PAGE_END  

% check for consistency
check(m);
 
if nargin<3,
	if isempty(m.model_code),
		model_code = {'productspace' 'inversedist' 'linear'};
	else
		model_code = m.model_code;
	end
end

error(checkargs({m n model_code},[2 3],'taksug','numeric','cell'));

% For compatibility purposes. Will be removed
if strcmp(model_code{1},'crossproduct'),
	model_code{1} = 'productspace';
end

if strcmp(model_code{2},'hyperbolic'),
	model_code{1} = 'inversedist';
end
%

antec_code=model_code{1};
memb_code=model_code{2};
conseq_code=model_code{3};
ni = get(m, 'n_in');
no = get(m, 'n_out');
nr = m.n_rules;

%check the inputs of the system
if get(m,'n_in')==0 & get(m,'n_out')==0
  error('number of inputs and number of outputs of the model have not been specified yet');
elseif get(m,'n_in')==0
  error('number of inputs of the model has not been specified yet');
elseif get(m,'n_out')==0
  error('number of outputs of the model has not been specified yet');
end

if isempty(m.model_code),
	m.model_code = model_code;
end
		
%First check if the rules we would like to add are compatible with the previous ones
if (strcmpi(m.model_code{1}, model_code{1}) & ...
	strcmpi(m.model_code{2}, model_code{2}) & ...
	strcmpi(m.model_code{3}, model_code{3})),
	
	in_dim = get(m,'n_in');
	
	if strcmpi(antec_code,'productspace') & (n>0),
	
		m.centers = [m.centers zeros(in_dim,n)];
		m.ivariances = 	cat(3,m.ivariances, reshape(repmat(eye(in_dim),[1 n]),[in_dim in_dim n]));
		curp = get(m,'optimparams');
		curp(find(curp > ni * nr * (ni + 1) )) = curp(find(curp > ni * nr * (ni + 1) )) + ni * ni * n;
		curp(find(curp > ni * nr)) = curp(find(curp > ni * nr)) + ni * n;
		
		curp = [curp ni*nr+(1:ni*n) ni*(nr+n)+ni*ni*nr+(1:ni*ni*n) ni*(nr+n)*(ni+1)+(ni+1)*no*nr+(1:(ni+1)*no*n)];
		curp = sort(curp);
		m = set(m,'optimparams',curp);
		
	elseif strcmpi(antec_code,'projected'),
	
		switch lower(memb_code),
		case 'standard',
		if (n>0),
			m.rls = [m.rls; ones(n,in_dim)];
			
			for i=1:in_dim,
				if isempty(m.mfs{i})
					m.mfs{i} = [1 0 0 0 0];
				end
			end
		end
		
		case 'rulegrid',
		
		nt = 1;
		for i=1:in_dim,	
			nt = nt * size(m.mfs{i},1);
		end
		
		if nt ~= 0,
			if n == -1,
				n = nt;
			end
			
			ref = cell(in_dim,1);
			lls = ref;
			
			for i=1:in_dim,
				lls{i} = 1:size(m.mfs{i},1);
			end
			
			[ref{:}] = ndgrid(lls{:});
			
			nref = reshape(cat(in_dim+1,ref{:}),[nt in_dim]);
			
			m.rls = [m.rls; nref(1:n,:)];
		else
			error(['Can define a grid of rules only if fuzzy sets are already' 13 ...
					'defined along every dimension of the input space. Please use add_sets first']);
		end
			
		otherwise,
		end
		
	end
	m.n_rules = m.n_rules + n;
	
	m.linears = cat(3,m.linears,zeros(get(m,'n_out'),in_dim+1,n));

else
	error('You cannot add rules of this type to the current model. Remove first the previous ones');
end





