function som_9_14(epochs)

% function som_9_14(epochs)
% 
% This program recreates Figure 9.14 from textbook.
% Use SOM to learn topology of input space of 'Escherichia coli' dataset.
% Note that this dataset has 8 features (7 numeric and 1 categorical), and
% 8 classes. We use 7 numeric features, and 3 most frequent classes, namely
% class no. 1, no. 2, and no. 8 ('cp', 'im', 'pp', respectively).
% 
% Inputs :  epochs      - number of training epochs.
% Outputs:  none.
%
% Author: Nemanja Djuric
% Date  : Sept. 25th, 2010
%
% Warning: Check line 47 of this file for compatibility issues.

% check input
if (epochs < 1)
    disp('Error: Invalid input, epochs must be a positive integer.');
    return;
end;

% definitions
def_som_size = 15;

% preprocessing, use only classes 1, 2, and 8.
data = create_ecoli_data();
class1 = find(data(:, 8) == 1)';
class2 = find(data(:, 8) == 2)';
class8 = find(data(:, 8) == 8)';
% rename class 8 to 3, easier to work with
data(class8, 8) = 3;
data = data([class1 class2 class8], :);

[len dim] = size(data);
num_features = dim - 1;

% shuffle data
[trash index] = sort(rand(size(data, 1), 1));
data = data(index,:);

% use 70% for training, and the remaining 30% for testing
[testdata traindata] = divideset(data, 70);

% first part is old version of newsom (tested on Matlab 7.0.0.19920), if 
%   it fails then new version of newsom is invoked (Matlab 7.7.0.471)
try
    % get range of features, needed for initialization of SOM
    min_max = minmax(traindata(:, 1 : num_features)');
    
    % create new SOM (old version)
    net = newsom(min_max, [def_som_size def_som_size], 'gridtop');
catch
    % create new SOM (new version)
    net = newsom(traindata(:, 1 : num_features)', [def_som_size def_som_size], 'gridtop');
end;

% train the SOM
net.trainParam.epochs = epochs;
net.trainParam.show = 10;
net = train(net, traindata(:, 1 : num_features)');

% use the learned weights to plot nice figure, using training data
plot_mat = zeros(def_som_size);
weights = net.iw{1, 1};
for i = 1 : length(traindata)
    point = traindata(i, :);
    label = point(end) * 10;
    
    for j = 1 : length(weights)
        dist(j) = eucl_dist(weights(j, :), point(1 : num_features));
    end;
    
    [trash ind] = min(dist);
    x_indice = ceil(ind / def_som_size);
    y_indice = ind - (x_indice - 1) * def_som_size;
    
    plot_mat(x_indice, y_indice) = label;
end;
icons = {'k.', 'rs', 'gv', 'b^'};
icon_color = {'k', 'r', 'g', 'b'};
class_names = {'cytoplasm', 'inner membrane without signal sequence', 'perisplasm'};
figure(1), clf;
hold on;
plot(1, 1, icons{1}, 'Markersize', 10, 'MarkerFaceColor', icon_color{1});
plot(1, 1, icons{2}, 'Markersize', 10, 'MarkerFaceColor', icon_color{2});
plot(1, 1, icons{3}, 'Markersize', 10, 'MarkerFaceColor', icon_color{3});
plot(1, 1, icons{4}, 'Markersize', 10, 'MarkerFaceColor', icon_color{4});
plot(1, 1, icons{1}, 'Markersize', 10, 'MarkerFaceColor', icon_color{1});
for i = 1 : def_som_size
    for j = 1 : def_som_size
        ind = plot_mat(i, j) / 10 + 1;
        plot(i, j, icons{ind}, 'Markersize', 20, 'MarkerFaceColor', icon_color{ind});
    end;
end;
legend('Neuron did not fire', class_names{1}, class_names{2}, class_names{3}, 'Location', 'SouthOutside');
t = title('SOM tested on training data (E. coli dataset)');
set(t,'fontsize', 14);
set(gca, 'XTick', [], 'YTick', []);

% use the learned weights to plot nice figure, using testing data
plot_mat = zeros(def_som_size);
weights = net.iw{1,1};
for i = 1 : length(testdata)
    point = testdata(i, :);
    label = point(end) * 10;
    
    for j = 1 : length(weights)
        dist(j) = eucl_dist(weights(j, :), point(1 : num_features));
    end;
    
    [trash ind] = min(dist);
    x_indice = ceil(ind / def_som_size);
    y_indice = ind - (x_indice - 1) * def_som_size;
    
    plot_mat(x_indice, y_indice) = label;
end;
icons = {'k.', 'rs', 'gv', 'b^'};
icon_color = {'k', 'r', 'g', 'b'};
class_names = {'cytoplasm', 'inner membrane without signal sequence', 'perisplasm'};
figure(2), clf;
hold on;
plot(1, 1, icons{1}, 'Markersize', 10, 'MarkerFaceColor', icon_color{1});
plot(1, 1, icons{2}, 'Markersize', 10, 'MarkerFaceColor', icon_color{2});
plot(1, 1, icons{3}, 'Markersize', 10, 'MarkerFaceColor', icon_color{3});
plot(1, 1, icons{4}, 'Markersize', 10, 'MarkerFaceColor', icon_color{4});
for i = 1 : def_som_size
    for j = 1 : def_som_size
        ind = plot_mat(i, j) / 10 + 1;
        plot(i, j, icons{ind}, 'Markersize', 20, 'MarkerFaceColor', icon_color{ind});
    end;
end;
legend('Neuron did not fire', class_names{1}, class_names{2}, class_names{3}, 'Location', 'SouthOutside');
t = title('SOM tested on testing data (E. coli dataset)');
set(t,'fontsize', 14);
set(gca, 'XTick', [], 'YTick', []);

pause;

try
    close(1);
catch
end;
try
    close(2);
catch
end;

% function that calculates Euclidean distance between points
function e_dist = eucl_dist(point1, point2)
e_dist = sqrt(sum((point1 - point2) .^2));