function [centers, assig, qe] = mvn_kmeans(models, k, t)
%MVN_KMEANS Compute K-Means clustering on the given mvn models in respect to the given divergence. Standard is the symmetric Kullback-Leibler divergence between the models.
%
%   [centers, assig] = MVN_KMEANS_SKL(models, k, type) computes a k-means
%   clustering using the given the SKL divergence. We return k mvn
%   centers and the assignment of the models to their centers.
%
%   See: Clustering with Bregman divergences, A. Banerjee et al., The
%   Journal of Machine Learning Research 2005, Volume 6.

%   (c) 2010-2011, Dominik Schnitzer, <dominik.schnitzer@ofai.at>
%   http://www.ofai.at/~dominik.schnitzer/mvn
%
%   This file is part of the MVN Octave/Matlab Toolbox
%   MVN is free software: you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation, either version 3 of the License, or
%   (at your option) any later version.
%
%   MVN is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You should have received a copy of the GNU General Public License
%   along with MVN.  If not, see <http://www.gnu.org/licenses/>.

    items = length(models);
    assig = zeros(items, 1);

    ri = randi(items, k, 1);
    centers = models(ri);

    if ((nargin < 2) || (nargin > 3))
         error('Wrong number of input arguments');
    end

    if (nargin < 3)
        t = 'skl';
    end
    
    if (strcmp(t, 'kl_left') == 1)
        mvn_div = @(x, c) mvn_div_kl(x, c);
        mvn_bregmancentroid = @(x) mvn_bregmancentroid_kl_left(x); 
        
    elseif (strcmp(t, 'kl_right') == 1)
        mvn_div = @(x, c) mvn_div_kl(c, x);
        mvn_bregmancentroid = @(x) mvn_bregmancentroid_kl_right(x); 
        
    elseif (strcmp(t, 'skl') == 1)
        mvn_div = @(x, c) mvn_div_skl(x, c);
        mvn_bregmancentroid = @(x) mvn_bregmancentroid_skl(x); 
        
    elseif (strcmp(t, 'skl_mid') == 1)
        mvn_div = @(x, c) mvn_div_skl(x, c);
        mvn_bregmancentroid = @(x) mvn_bregmancentroid_skl(x, 1);
        
%    elseif (strcmp(t, 'js') == 1)
%        mvn_div = @(x, c) mvn_div_js(x, c, 0);
%        mvn_bregmancentroid = @(x) mvn_bregmancentroid_js(x, 1);
%        
%    elseif (strcmp(t, 'js_mid') == 1)
%        mvn_div = @(x, c) mvn_div_js(x, c);
%        mvn_bregmancentroid = @(x) mvn_bregmancentroid_js(x, 1);
%        
%    elseif (strcmp(t, 'burbearao') == 1)
%        mvn_div = @(x, c) mvn_div_js(x, c);
%        mvn_bregmancentroid = @(x) mvn_bregmancentroid_burbearao(x);
        
    else
        error('Unknown divergence given.');
    end

    iter = 0;
    oldqe = 1;
    qe = 0;
  
    reiterate = 3;
    while (reiterate > 0)

        % assign the models to their closest centroid	
        oldqe = qe;
        qe = 0;
        for i = 1:items
            c = intmax();
            cidx = k+1;
            for j = 1:k
                dist = mvn_div(models(i), centers(j));
                if (dist < c)
                    c = dist;
                    cidx = j;
                end
            end
            qe = qe + c;
            assig(i) = cidx;
        end
        qe = qe/items;
        fprintf('#%d, average bregman quantization error = %f\n', iter, qe);

        % check for failing clentroids
        reiterate = max(reiterate - 1, 0);
        i = 1;
        while (i <= k)
            sel = find(assig == i);
            if (length(sel) < 1)
                fprintf('%d, reinitializing centroid #%d (%d)\n', ...
                    iter, i, length(sel));
                r = randi(items, 1, 1);
                centers(i) = models(r);
                assig(r) = i;
                reiterate = reiterate + 3;
                i=0;
            end
            i = i+1;
        end
        
        % compute the new centroids
        for i = 1:k
            aaa = mvn_bregmancentroid(models(assig == i));
%            fprintf('centroids = %d = %d, %d\n', i , length(aaa), length(models(assig == i)));
            centers(i) = aaa;
        end

        iter = iter + 1;
        
        if (((oldqe - qe) >= 0.0001) && (reiterate == 0))
            reiterate = 1;
        end
    end

    % assign the models to their closest centroid	
    for i = 1:items
        c = intmax();
        cidx = k+1;
        for j = 1:k
            dist = mvn_div(models(i), centers(j));
            if (dist < c)
                c = dist;
                cidx = j;
            end
        end
        assig(i) = cidx;
    end
end
