function [ S, B ] = asso( C, k, tau, w_plus, w_minus )
%ASSO implements Mietine's ASSO algorithm for the Boolean matrix decomposition
% direct implementation of pseudocode (not optimized)
% return Boolean matrices S and B for which C \aproxeq S \circ B

% k represents the number of factors
% tau \in [0, 1], ideal 0.9
% w_plus, w_minus \in R, ideal w_plus = w_minus = 1


[m, n] = size(C);
S = logical([]); B = logical([]);
covered = false(m,n);
A = false(1);
a = logical([]);
b = logical([]);

% association matrix A
for i=1:n
    for j=1:n
        A(i,j) = ((sum(C(:,i) .* C(:,j))/sum(C(:,i))) >= tau);
    end
end

% select k basis vectors
for l=1:k
    display(l);
    best_cover = -Inf;
    best_rowcount = false(m,1);

    % for each row of A
    for i=1:size(A,1)
        cover = 0;
        rowcount = zeros(m,1);
        row = A(i,:);

        % compare with original matrix
        for j=1:m
            for o=1:n
                % plus
                if C(j,o) && row(o)
                    rowcount(j) = rowcount(j) + w_plus * (C(j,o) - covered(j,o));
                    % minus
                elseif ~C(j,o) && row(o)
                    rowcount(j) = rowcount(j) - w_minus * (1 - covered(j,o));
                end
            end

            if rowcount(j)>0
                cover = cover + rowcount(j);
            end
        end

        if cover >= best_cover
            best_cover = cover;
            best = i;
            best_rowcount = (rowcount > 0);
        end
    end

    % the best result
    B = [B; A(best,:)];
    S = [S, best_rowcount];


    % already covered part
    for p=1:m
        if best_rowcount(p) > 0
            for q=1:n
                if A(best,q)
                    covered(p,q) = 1;
                end
            end
        end
    end

    % remove selected row of A
    A(best,:) = [];
end

end
