Complement_Code.m


function complementCodedData = Complement_Code(data,varargin)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Complement coding:  Learning both absent and present features
%
% Carpenter, G. A., Grossberg, S., & Rosen, D.B. (1991)
% Fuzzy ART: Fast stable learning and categorization of analog patterns by an
% adaptive resonance system.
% Neural Networks, 4, 759-771.
% http://profusion.bu.edu/techlab/modules/mydownloads/singlefile.php?cid=26&lid=10
%
% Complement coding allows an ART system to encode within its critical
% feature patterns of memory features that are consistently absent
% on an equal basis with features that are consistently present.
% Complement codes the data for use with an ART network.
% vertical is M, the FEATURES
% Horizontal is N, the NUMBER of data points.
% USAGE:
% (1) Complement_Code(data)
% data is either a single row vector, or a matrix of size (N,M) with M features as column
% vectors.
% (2) Complement_Code(data,min_vect,max_vect)
% data: input data, min_vect: vector of minimum features, max_vect: vector
% of maximum_features
% data, min_vect, and max_vect should all have M rows
% complementCodedData = [data; 1-data];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


if (nargin==1)
    %All features need to be scaled into the [0 1] range prior to
    %complement coding
    disp('Deriving min and max feature values from data');
    disp('Number of input records: ');
    disp(size(data,1));
    %Find minimum feature values in input data
    min_vect=min(data,[],1);
    temp_max_vect=max(data,[],1);
    disp('Minimum feature values: ');
    disp(min_vect);

    %Select features where minimum and maximum are not equal
    min_vect=min_vect.*(temp_max_vect~=min_vect);
    %Shift features such that all features are >= 0
    data=data-repmat(min_vect,size(data,1),1);

    %Find maximum feature values in shifted input data
    max_vect=max(data,[],1);
    disp('Maximum feature values: ');
    disp(max_vect);

    %Select features where maximum>1
    max_vect=max_vect.*(max_vect>1)+(max_vect<=1);

    %Rescale such that all features are <= 1
    data=data./repmat(max_vect,size(data,1),1);


elseif (nargin==3)
    num_features=size(data,2);
    min_vect=varargin{1};
    max_vect=varargin{2};
    if (num_features~=size(min_vect,2)) || (num_features~=size(max_vect,2))
        eval('help Complement_Code');
        error('Number of features are unequal in the provided data, minimum feature vector and maximum feature vector');
    end
    if (sum((min_vect>max_vect))>0)
        eval('help Complement_Code');
        error('One or more feature values in the minimum feature vector are greater than corresponding values in maximum feature vector!');

    end

    %Truncating data into the ranges provided by min_vect and max_vect
    
    %Equate features with equal min and max to zero
    min_vect=min_vect.*(min_vect~=max_vect);
    
    disp('Rescaling data into provided range');
    data=max(data,repmat(min_vect,size(data,1),1))-repmat(min_vect,size(data,1),1);
    data=min(data,repmat(max_vect-min_vect,size(data,1),1));

    % Rescaling all features into [0 1] range; eps ensures there are no
    % divide-by-zero errors
    data=data./repmat(max_vect-min_vect+eps,size(data,1),1);

else
    eval('help Complement_Code');
    error('One or three inputs needed');

end




complementCodedData = [data 1-data];


% Do the complement coding for each sample.