function DV = GGCCD(type2FS, defuzzMethod);

% DV = GGCCD(type2FS, defuzzMethod);
% defuzzifies a generalised type-2 fuzzy set to give an x-value
% firstly type reduces the type-2 fuzzy set to a type-1 fuzzy set using GGCCD,
% secondly defuzzifies the type-1 set using defuzzMethod
%
% SG 290317, revised 080917, 090518

% TYPE REDUCTION [(x,u,z) --> (x,z)] --------------------------------------

matrixSize = size(type2FS);
domainSize = matrixSize(2);
codomainSize = matrixSize(1);

xVector = 0:1/(domainSize-1):1;  % notches on x-axis
uVector = 0:1/(codomainSize-1):1;  % notches on u-axis
VSCuVector = linspace(0,0,domainSize); % initialise centroids of each VS (relative to codomain)
LMFuVector = linspace(0,0,domainSize); % initialise LMF primary membership grades
LMFzVector = []; % initialise vector of LMF secondary membership grades (z_0^j)
rVector  = linspace(0,0,domainSize); % initialise blur vector
rVectorCumul = linspace(0,0,domainSize); % initialise cumulative blur vector
GRESAvector = linspace(0,0,domainSize); % initialise GRESA (type-1 fuzzy set)
GRESAzVector = linspace(1,1,domainSize); % initialise z values of GRESA vector (to 1 as the minimum operator will be applied).
GRESAzMatrix = zeros(codomainSize,domainSize); % initialise minimum z values of embedded sets of collapsing slice (Z_B_i^I)
sumGRESAzMatrixVector = linspace(0,0,domainSize); % initialise sum of z values on each slice of GRESAzMatrix (||B_I||)
SMGcollapsedSliceVector = linspace(0,0,domainSize); % initialise secondary membership grades of collapsed slices (z_R^I)
blurMatrix = zeros(codomainSize, domainSize); % initialise blur matrix
zGradeMinIndex = linspace(0,0,domainSize); % initialise index of first non zero z-grade on each VS
zGradeMaxIndex = linspace(0,0,domainSize); % initialise index of last non zero z-grade on each VS
numPointsOnSliceVector =  linspace(0,0,codomainSize); % initialise number of non-zero points on each slice

sumSecGradesVSvector = sum(type2FS); % sums of secondary grades on VSs

for columnCounter = 1:domainSize % work through all the VSs
    zVector = type2FS(:,columnCounter); % z grades on the VS
    zGradeIndex = find(type2FS(:,columnCounter)); % find indices of codomain with non-zero z grades
    zGradeMinIndex(columnCounter) = min(zGradeIndex);
    zGradeMaxIndex(columnCounter) = max(zGradeIndex);
end
numPointsOnSlice = zGradeMaxIndex + 1 - zGradeMinIndex;

for columnCounter = 1:domainSize % work through all the VSs
    LMFuIndexVector(columnCounter) = find(type2FS(:,columnCounter)~=0, 1, 'first'); % vector of codomain indices of first non-zero elements of each VS
    UMFuIndexVector(columnCounter) = find(type2FS(:,columnCounter)~=0, 1, 'last'); % vector of codomain indices of last non-zero elements of each VS
end

for columnCounter = 1:domainSize % work through all the VSs
    LMFz = type2FS(LMFuIndexVector(columnCounter), columnCounter);
    LMFzVector = [LMFzVector LMFz]; % vector of LMF secondary membership grades (z_0^j)
end

LMFuVector = (LMFuIndexVector-1)/(codomainSize-1); % vector of u grade of LMF
scalarCardLMF = sum(LMFuVector); % scalar cardinality of LMF (||L||)

for columnCounter = 1:domainSize % work through all the VSs
    for rowCounter = LMFuIndexVector(columnCounter):UMFuIndexVector(columnCounter) % work through all non-zero elements on the VSs
        blurMatrix(rowCounter, columnCounter) = (rowCounter - LMFuIndexVector(columnCounter))/(codomainSize-1); %- type2FS(columnCounter, LMFuIndexVector(columnCounter)) % blur of each primary membership grade relative to LMF (B^I_i)
    end
end

innerFraction = 0;
for i = zGradeMinIndex(1):zGradeMaxIndex(1)
    GRESAzVector(1) = min((type2FS(i,1)), min(LMFzVector));
    innerFraction = innerFraction + ((blurMatrix(i, 1) * GRESAzVector(1)) / (scalarCardLMF + blurMatrix(i, 1)));
    GRESAzMatrix(i,1) = GRESAzVector(1);
end
sumGRESAzMatrixVector(1) = sum(GRESAzMatrix(:,1));
SMGcollapsedSliceVector(1) = sumGRESAzMatrixVector(1)/numPointsOnSlice(1); % secondary membership grade of Collapsed Slice 1

rVector(1) = (scalarCardLMF*innerFraction)/(sumSecGradesVSvector(1)-innerFraction);
rVectorCumul(1) = rVector(1);
for columnCounter = 2:domainSize % work through all the VSs from Slice 2 onwards
    innerFraction = 0;
    for i = zGradeMinIndex(columnCounter):zGradeMaxIndex(columnCounter)
        GRESAzVector(columnCounter) = min([min(SMGcollapsedSliceVector(1:columnCounter-1)) type2FS(i,columnCounter) min(LMFzVector(columnCounter+1:end))]);
        innerFraction = innerFraction + ((blurMatrix(i, columnCounter) * min((type2FS(i,columnCounter)), min(LMFzVector))) / (scalarCardLMF + rVectorCumul(columnCounter-1) + blurMatrix(i, columnCounter)));
        GRESAzMatrix(i,columnCounter) = GRESAzVector(columnCounter-1);
    end
    sumGRESAzMatrixVector(columnCounter) = sum(GRESAzMatrix(:,columnCounter));
    SMGcollapsedSliceVector(columnCounter) = sumGRESAzMatrixVector(columnCounter)/numPointsOnSlice(columnCounter); % secondary membership grade of collapsed slice
    rVector(columnCounter) = ((scalarCardLMF + rVectorCumul(columnCounter-1))*innerFraction)/(sumSecGradesVSvector(columnCounter)-innerFraction);
    rVectorCumul(columnCounter) = rVector(columnCounter) + rVectorCumul(columnCounter-1);
end

GRESAvector = LMFuVector + rVector;

% DEFUZZIFICATION [(x,z) --> x] -------------------------------------------

DV = defuzz(xVector, GRESAvector, defuzzMethod); % defuzzify the type-1 fuzzy set 

%
% % PLOT GRESA (OPTIONAL: UNCOMMENT)
% plot(xVector, GRESAvector, 'LineWidth',2)
% xlabel('primary domain')
% ylabel('secondary domain')

