% data is the data set. Each data vector should be a row vector in a matrix.
% numTestUsers is the number from the data set that will be set aside and not
%    used in training.
% minNumRatings is number of ratings given to the system for a test case before
%    evaluation
%
% Assumptions:
%   missing data is a 0.

function [logLikeRandom, lossRandom, logLikeVOI, lossVOI] = ...
    testVoi(data,numTestUsers,minNumRatings,A,G,M,W,...
    trainIndices,iters,numVQs,numCompsPerVQ,var_m, var_g)
 
%the number of data vectors
N = size(data,1);
 
%the dimension of each data vector
D = size(data,2)
 
%maxRated is the maximum number of items that a user could have voted
%   upon.
maxRated = D-minNumRatings;

%Records log likelihood for the held out data for a user
logLikeRandom = zeros(numTestUsers,maxRated);
logLikeVOI = zeros(numTestUsers,maxRated);
 
%The loss associated with each recommendation
lossRandom = zeros(numTestUsers,maxRated);
lossVOI = zeros(numTestUsers, maxRated);
 
%constant representing marker for missing data.
mD=0;
 
%The following indices are indices to users (rows) from the data;
%temp=randperm(N);
%testIndices=temp(1:numTestUsers);
%trainIndices=temp(numTestUsers+1:end);
% 
%trainData = data(trainIndices,:);

%% *model-specific* Training?
%[A,G,M,W] = MCVQ(trainData,numVQs,numCompsPerVQ,iters); 

for i=1:numTestUsers
  testUser = testIndices(i);
  testUserRatings=data(testUser,:);

  %Finding the indices to the data vector that have values (not missing) 
  votedOnIndices = find(testUserRatings~=mD);
 
  %Separating the rating vector for the user to known and hidden.
  temp = randperm(length(votedOnIndices));

  knownIndices = votedOnIndices(temp(1:minNumRatings));
  heldOutIndices = votedOnIndices(temp(minNumRatings+1:end));
  numHeldOut = length(heldOutIndices);
 
  %This vector will be the ratings for this user, except with all values
  % not part of knownIndices are 0.
  knownRatings = zeros(1,D);  
  % making a copy of testUserRatings with all but knownRatings zeroed out
  for j=knownIndices knownRatings(j) = testUserRatings(j); end

  %%%%%%%%%%%%%%%%%
  %Testing without value of information - random selection of next movie
  for numAdded = 1:numHeldOut
    %% *model-specific* compute expected values for still heldOutRatings
    % inferredRatings = MCVQ_infer(knownRatings,numVQs,numCompsPerVQ,...
    %     A,G,M,W,var_m, var_g);
    inferredRatings = 5 * rand(1,D);
    inferredHeldOut = zeros(1,D);
    for j=heldOutIndices inferredHeldOut(j) = inferredRatings(j); end;
    heldOutPdf = ratingPdf(inferredHeldOut);
    
    %select top pick
    [maxModelRating,topPick] = max(inferredHeldOut);
  
    %record the difference between the best pick and the model's topPick
    lossRandom(i,numAdded) = abs(max(testUserRatings) - maxModelRating);  
 
    %compute logLikely using the pdfs over heldOutRatings
    logLikeRandom(i,numAdded) = ... 
         logLikelihood(heldOutPdf,testUserRatings,heldOutIndices);

    %add a new rating index to knownRatings and removing it from those
    %  that are held out. 
    addedRatingIndex = heldOutIndices(1);
    knownRatings(addedRatingIndex) = testUserRatings(addedRatingIndex);
    knownIndices = [knownIndices addedRatingIndex];
    heldOutIndices = [heldOutIndices(2:end)];
  end
 
  %%%%%%%%%%%%%%%%
  %Testing with VOI -- adding heldout data to model using VOI

  knownIndices = votedOnIndices(temp(1:minNumRatings));
  heldOutIndices = votedOnIndices(temp(minNumRatings+1:end));
  numHeldOut = length(heldOutIndices);
  knownRatings = zeros(1,D);
  for j=knownIndices knownRatings(j) = testUserRatings(j); end

  for numAdded = 1:numHeldOut
    %% *model-specific* compute expected values for still heldOutRatings
    % inferredRatings = MCVQ_infer(knownRatings,numVQs,numCompsPerVQ,A,G,M,W);
    inferredRatings = 5 * rand(1,D);
    inferredHeldOut = zeros(1,D);
    for j=heldOutIndices inferredHeldOut(j) = inferredRatings(j); end;
    heldOutPdf = ratingPdf(inferredHeldOut);
    
    %select top pick
    [maxModelRating,topPick] = max(inferredHeldOut);
  
    %record the difference between the best pick and the model's topPick
    lossVOI(i,numAdded) = abs(max(testUserRatings) - maxModelRating);  
 
    %compute logLikely using the pdfs over heldOutRatings
    logLikeVOI(i,numAdded) = ... 
         logLikelihood(heldOutPdf,testUserRatings,heldOutIndices);

    %compute EVOI
    evoiHeldOut = compVoi(heldOutIndices,knownRatings,heldOutPdf);
    [maxEvoi,indexMaxEVOI] = max(evoiHeldOut);
   
    %Add a new rating index to knownRatings and removing it from those
    %   that are held out. 
    knownRatings(indexMaxEVOI) = testUserRatings(indexMaxEVOI);
    knownIndices = [knownIndices indexMaxEVOI];
    heldOutIndices = heldOutIndices(find(heldOutIndices~=indexMaxEVOI));
  end
end
