%% How to use matrix-vector products to compute tag similarity
% A week or so ago, I got a question from a startup company in Palo Alto.
% 
%  I've got a database of products and tags.  Given a product
%  p, I want to find sort products by the number of tags they have
%  in common with p.  I think I need to do something with the
%  power set of tags.

%% Solution
% To solve this problem, we first construct a product-by-tag matrix:
%  
%   P(i,j) = 1 if product i has tag j
%
% Recall the output of a matrix vector product:
%
%   row i of P*x = sum over j of P(i,j)*x(j)
%
% So the vector x describes tags.  If x only has zeros and ones, then
% P(i,j)*x(j) is only 1 if both product i and x have tag j.


%% A baby example
% 8 products, 5 tags

products = {'panasonic gf1','canon 1ds','olympus ep1',...
            'nikon d3100', 'canon t3', 'sony a900', 'nikon d3x', ...
            'samsung nx10'};
tags = {'small','heavy','easy','consumer','good'};
P = zeros(8,5);
% panasonic gf1 = small, easy, consumer, good
P(1,1) = 1;
P(1,3) = 1;
P(1,4) = 1;
P(1,5) = 1;
% canon 1ds = heavy, good
P(2,2) = 1;
P(2,5) = 1;
% olympus epl1 = small, consumer, easy
P(3,1) = 1;
P(3,3) = 1;
P(3,4) = 1;
% nikon d3100 = consumer, good
P(4,4) = 1;
P(4,5) = 1;
% canon t3 = consumer, good, heavy
P(5,4) = 1;
P(5,5) = 1;
P(5,2) = 1;
% sony a900 = heavy, easy
P(6,2) = 1;
P(6,3) = 1;
% nikon d3x = good
P(7,5) = 1;
% samsung nx10 = small, easy
P(8,1) = 1;
P(8,3) = 1;

%% Find number of tags in common with gf1
% Use the row of P for the GF1 as the vector
x = P(1,:)'

%% Do the mat-vec
y = P*x

%% Sort products by number of tags
[ignore p] = sort(y,'descend');
products(p)

%% Same demo, but with lastfm data
cd ~/data/lastfm-plamere/Lastfm-ArtistTags2007
help load_lastfm_data

%% Get the artists and tags
[A,artists,tags] = load_lastfm_data;

%% Ignore counts
B = spones(A); % B is a matrix with only ones and zeros

%%
artistrow = strmatch('Radiohead',artists)

%% Find the tags that Radiohead has
x = B(artistrow,:)';
tags(find(x))

%% Look at the other artists with many tags
y = A*x;
[ignore p] = sort(y,'descend');
artists(p(1:25))
