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.