%
%  CIS 8603
%  Project 2: Semi-Supervised Learning
%
%  Team Members:
%                Semir Elezovikj
%                Mo'taz Abdul Aziz Ali Al-Hami
%                Howard Liu
%

function [z_UU,accuracy]=ssl(PLL, PLU, PUL, PUU, True_LL)
YL = eye(70,70);
% Alpha is a fraction of label information
Alpha=0.9999;
% the formula try to propagate label information through neighbors 
fU=(1-Alpha)*inv(eye(1330,1330)-Alpha*PUU)*PUL*YL;


% label bidding:
z_UU=step_heap_sort(fU);

end

% function for label bidding, comes from a modified heapsort
function z_UU=step_heap_sort(fU_2d)

% 1330*70=93100 and 93100/2=46550

fU=zeros(1,93100);      % flattened 1-dimension fU

% for each entry in fU, we have...
class=zeros(1,93100);   % its corresponding class number (column numbers of fU_2d)
z_order=zeros(1,93100); % and its corresponding unlabeled data point number (row numbers of fU_2d)

% fill up all values from original 2-dimension fU
for i=1:1330
    for j=1:70
        fU(1,(i-1)*70+j)=fU_2d(i,j);
        class(1,(i-1)*70+j)=j;      % column numbers of fU_2d
        z_order(1,(i-1)*70+j)=i;    % row numbers of fU_2d
    end
end

% pointer to the last node in the heap
last = 93100;

% buld max-heap
for node=46550:-1:1
    
    % shift-down (max-heap reheap)
    while node <= last
        left = node*2;
        right = left+1;
        swap = 0;
        if right <= last    % has left and right child
            if fU(1,left) > fU(1,right)
                if fU(1,left) > fU(1,node)    % left child is max, swap node and left child
                    swap = fU(1,left);
                    fU(1,left) = fU(1,node);
                    fU(1,node) = swap;
                    
                    swap = class(1,left);
                    class(1,left) = class(1,node);
                    class(1,node) = swap;
                    
                    swap = z_order(1,left);
                    z_order(1,left) = z_order(1,node);
                    z_order(1,node) = swap;
                    
                    node = left;
                    continue;
                else
                    break;
                end
            else                               % has left and right child and...
                if fU(1,right) > fU(1,node)    % right child is max, swap node and right child
                    swap = fU(1,right);
                    fU(1,right) = fU(1,node);
                    fU(1,node) = swap;
                    
                    swap = class(1,right);
                    class(1,right) = class(1,node);
                    class(1,node) = swap;
                    
                    swap = z_order(1,right);
                    z_order(1,right) = z_order(1,node);
                    z_order(1,node) = swap;
                    
                    node  = right;
                    continue;
                else
                    break;
                end
            end
            
        elseif left <= last    % only has left child and...
            if fU(1,left) > fU(1,node)    % left is max, swap node and left child
                swap = fU(1,left);
                fU(1,left) = fU(1,node);
                fU(1,node) = swap;
                
                swap = class(1,left);
                class(1,left) = class(1,node);
                class(1,node) = swap;
                
                swap = z_order(1,left);
                z_order(1,left) = z_order(1,node);
                z_order(1,node) = swap;
            end
            break;
        else    % no child
            break;
        end
    end
    % end of shift-down (max-heap reheap)
    
end    % max-heap built

z_UU=zeros(1330,1);
numClassLabels=ones(70,1)*19;   % each class has 19 labels in total
filled_count=0;

% main loop in heapsort:
%     - take the maximun/root node, replace it with the last node, then reheap
%     - repeat the process for n times
for i=1:93100
    % If there's enough labels left for the corresponding class
    %    and the corresponding data point in z_UU is not yet labeled
    % Then assign a label to the data point
    if numClassLabels(class(1,1),1) > 0 && z_UU(z_order(1,1),1) == 0
        z_UU(z_order(1,1),1) = class(1,1);
        numClassLabels(class(1,1),1)=numClassLabels(class(1,1),1)-1;
        filled_count=filled_count+1;
        
        % if all data points in z_UU are labeled, we can break from sorting early
        if filled_count >= 1330
            %iterations = i
            break;    % finish early. We don't need to sort the whole list.
        end
        
    else
        % If there's no labels left for the corresponding class
        %    or the corresponding data point in z_UU is already labeled
        % Then skip
    end
    
    
    % For the last node, if there's no labels left for its corresponding class
    %    or its corresponding data point in z_UU is already labeled
    % Then we can also skip the last
    while last>1 && (numClassLabels(class(1,last),1) == 0 || z_UU(z_order(1,last),1) ~= 0)
        last = last-1;
    end
    
    % copy last to first/root
    fU(1,1)=fU(1,last);
    class(1,1)=class(1,last);
    z_order(1,1)=z_order(1,last);
    last=last-1;
    
    
    % shift-down (max-heap reheap)
    node = 1;
    while node <= last
        left = node*2;
        right = left+1;
        swap = 0;
        if right <= last    % has left and right child
            if fU(1,left) > fU(1,right)
                if fU(1,left) > fU(1,node)    % left is max
                    swap = fU(1,left);
                    fU(1,left) = fU(1,node);
                    fU(1,node) = swap;
                    
                    swap = class(1,left);
                    class(1,left) = class(1,node);
                    class(1,node) = swap;
                    
                    swap = z_order(1,left);
                    z_order(1,left) = z_order(1,node);
                    z_order(1,node) = swap;
                    
                    node = left;
                    continue;
                else
                    break;
                end
            else
                if fU(1,right) > fU(1,node)    % right is max
                    swap = fU(1,right);
                    fU(1,right) = fU(1,node);
                    fU(1,node) = swap;
                    
                    swap = class(1,right);
                    class(1,right) = class(1,node);
                    class(1,node) = swap;
                    
                    swap = z_order(1,right);
                    z_order(1,right) = z_order(1,node);
                    z_order(1,node) = swap;
                    
                    node  = right;
                    continue;
                else
                    break;
                end
            end
            
        elseif left <= last    % only has left child
            if fU(1,left) > fU(1,node)    % left is max
                swap = fU(1,left);
                fU(1,left) = fU(1,node);
                fU(1,node) = swap;
                
                swap = class(1,left);
                class(1,left) = class(1,node);
                class(1,node) = swap;
                
                swap = z_order(1,left);
                z_order(1,left) = z_order(1,node);
                z_order(1,node) = swap;
            end
            break;
        else    % no child
            break;
        end
    end
    % end of shift-down (max-heap reheap)
    
    
    
    
end


end


