%% extend_nary2.m

%% This function uses Zadeh's Extension Principle (Section 7.2 in the 
%% book Uncertain Rule-Based Fuzzy Logic Systems: Introduction and 
%% New Directions, by Jerry M. Mendel, and published by Prentice-Hall, 
%% 2000.) to extend an "n"-ary operation "op_n" to "n" type-1 fuzzy sets. 

%% Written by Nilesh N. Karnik - July 22,1998
%% For use with MATLAB 5.1 or higher.

%% NOTE : This program uses a much smaller amount of memory 
%% compared to "extend_nary1.m"; and, correspondingly, is quite slow.
%% It can, however, be used for any values of "m" and "n", in general.
%% For performing a weighted averaging operation, a better program -
%% one which uses even a smaller amount of memory - is 
%% "weighted_avg.m".
 
%% Outputs : "out" and "mem" (column vectors) are, respectively, 
%% the domain and the memberships of the result of the extended 
%% "op_n" operation. 

%% Inputs : "X" is an "n x m" matrix, containing the domain elements 
%% of the "n" type-1 sets (the domain of each set is assumed to 
%% contain "m" elements). "Y" has the same size as "X" and contains
%% the memberships of the points in "X". "op_n" is a string (entered 
%% in inverted commas, as " 'op_n' ") containing the name of the 
%% function which defines the  n-ary operation to be extended (the 
%% function should be stored in the file "op_n.m"). If "tnorm" < 0 
%% (scalar), minimum t-norm is used, otherwise product t-norm is used. 
%% "step" (scalar) is an optional parameter. If it is not provided, the 
%% "n" type-1 sets are assumed to have discrete domains and the output 
%% is presented just by sorting the result of the extended "op_n" 
%% operation. If "step" is provided, it is assumed that the "n" type-1 
%% sets actually have continuous domains and are discretized for 
%% computing purposes. The resulting type-1 set, in this case, has 
%% equispaced domain points : "[minx : step : maxx]", where "minx" and 
%% "maxx" are, respectively, the minimum and the maximum of the results 
%% of the "op_n" operation between domain elements of the participating 
%% type-1 sets. 
 
%% Note 1 : The t-conorm used is maximum.
%% Note 2 : If "op_n" is a built-in function, you may have to use the 
%% MATLAB function "builtin" rather than "feval".
%% Note 3 : The function "op" should be written so that it can work 
%% with matrices, and perform the n-ary operation on each column of the 
%% matrix, similar to the MATLAB functions "min(X)" or "prod(X)", where 
%% "X" is a matrix. As an example, see the function "wt_avg_op.m".
 
%% Uses function "trimvec.m" .


function[out,mem] = extend_nary2(X,Y,op_n,tnorm,step)

[n,m] = size(X) ;

X1 = X ;
Y1 = Y ;

lm = m^(n-1) ;
temp1 = zeros(1,m) ;
temp2 = temp1 ;

xout = zeros(1,lm*m) ;
memout = zeros(1,lm*m) ;

for i1 = 1 : lm,
    xout(m*(i1-1)+1 : m*i1) = feval(op_n,X1) ;

    if tnorm < 0,
       memout(m*(i1-1)+1 : m*i1) = min(Y1) ;
    else
       memout(m*(i1-1)+1 : m*i1) = prod(Y1) ;
    end  %% if minflag


    temp1(1:m-1) = X1(n,2:m) ;
    temp1(m) = X1(n,1) ;
    X1(n,:) = temp1 ;    
    
    temp2(1:m-1) = Y1(n,2:m) ;
    temp2(m) = Y1(n,1) ;
    Y1(n,:) = temp2 ;    

    for i2 = 1 : n-1,
        if mod(i1,m^i2) == 0,

           temp1(1:m-1) = X1(n-i2,2:m) ;
           temp1(m) = X1(n-i2,1) ;
           X1(n-i2,:) = temp1 ;    
           
           temp2(1:m-1) = Y1(n-i2,2:m) ;
           temp2(m) = Y1(n-i2,1) ;
           Y1(n-i2,:) = temp2 ;    

       end %% if mod(i1,m^i2)
    end   %%% for i2

end   %%% for i1


if nargin == 4,

    [out,mem] = trimvec(xout,memout) ;

else 
    
    minx = min(xout) ;
    maxx = max(xout) ;    
   
    eps = step/2 ;
    i2 = 1 ;
    for k = minx : step : maxx,
        out(i2) = k ;
        in1 = find(abs(xout-k) <= eps) ;

        if ~isempty(in1),
            mem(i2) = max(memout(in1)) ;
        else 
            mem(i2) = mem(i2-1) ;
        end   %%% if 
        
        i2 = i2 + 1;
    end   %% for k
    if k ~= maxx,
        out(i2) = maxx ;
        in1 = find(abs(xout-maxx) <= eps) ;

        if ~isempty(in1),
            mem(i2) = max(memout(in1)) ;
        else 
            mem(i2) = mem(i2-1) ;
        end   %%% if ~isempty
    end   % if k      


end % if nargin

return ; 
