function [ data, attData, missing_nodes_mapping ] = RemoveRandomNodes3( data, attData, totalAttNum, num_missing_nodes, missing_nodes_mapping, non_neighbors_distance, missingNodesInput )
    %RemoveRandomNodes Remove num_missing_nodes from data. If some nodes are
    %removed already, provide missing_nodes_mapping
    %   Detailed explanation goes here

    if nargin >= 7 % i.e. getting  missingNodesInput
        missing_nodes = missingNodesInput;
    else
        %%data_orig = data;
        numAttPerPH = 0;

        % if the mapping is larger than the number of nodes we want to remove, empty
        % it and start a new mapping. This can happen if we finished looping over
        % the number of missing nodes and started a new iteration of an outer loop.
        if size(missing_nodes_mapping,2) > num_missing_nodes
            missing_nodes_mapping = [];
            num_nodes_to_remove = num_missing_nodes;
        else
            num_nodes_to_remove = num_missing_nodes - size(missing_nodes_mapping,2);
        end

        % randomly choose missing nodes
        %missing_nodes = ChooseMissingNodes_old(num_nodes_to_remove, data, missing_nodes_mapping, non_neighbors_distance);
        missing_nodes = ChooseMissingNodes(num_nodes_to_remove, data, attData, totalAttNum, numAttPerPH, missing_nodes_mapping);

        %sort the list and create a list of the new nodes that each missing node is mapped to - each link 
        %to a missing node is replaced by a link to a new, "UNK" node
        missing_nodes = sort( unique(missing_nodes) , 'descend');
        missing_nodes_mapping = missing_nodes;

        %replace each link to a missing node with a link to a new node
        %find all missing node neighbors
        missing_nodes_all_neighbors = zeros(1, size(data,2));
        for curr_nissing_node = missing_nodes
            missing_nodes_all_neighbors = missing_nodes_all_neighbors | data(curr_nissing_node,:);
        end
        missing_nodes_all_neighbors = find(missing_nodes_all_neighbors);
        %for each node in missing_nodes_all_neighbors add edges to placeholder
        for i = missing_nodes_all_neighbors
            neighbors = find(data(i,:));
            missing_neighbors = intersect(neighbors, missing_nodes);
            missing_neighbors = sort(missing_neighbors, 'descend');
            for curr_missing_neighbor = missing_neighbors
                if data(i,curr_missing_neighbor) == 1
                    % append col & row for the placeholder
                    data = ExpandDataByOne(data, i, non_neighbors_distance);
                    attData = ExpandAttByOne(attData, curr_missing_neighbor, non_neighbors_distance, totalAttNum, numAttPerPH);
                    %add the new UNK node to the missing nodes mapping j is the index of the missing node
                    %look for the first zero in column j of the missing nodes mapping and put the new node
                    %index there
                    added_node = 0;
                    %add it in the first position which equals zero
                    j = find(missing_nodes == curr_missing_neighbor, 1);
                    for k = 1 : size(missing_nodes_mapping,1)
                        if missing_nodes_mapping(k, j) == 0
                            %if we start with 1000 nodes, and we have 5 missing nodes, after
                            %adding one node at this point, the size of the graph is 1001. 5 nodes
                            %will be removed so the correct index of the new node will be 1001 - 5 = 996.
                            %The next one is 997 and so on.
                            missing_nodes_mapping(k, j) = size(data,1) - num_missing_nodes;
                            added_node = 1;
                            break;
                        end
                    end
                    %if all the column is non-zero, add a new row and put it there
                    if added_node == 0
                        missing_nodes_mapping = [missing_nodes_mapping; zeros(1, size(missing_nodes_mapping,2))];
                        missing_nodes_mapping(size(missing_nodes_mapping,1), j) = size(data,1) - num_missing_nodes;
                    end
                end %if friend
            end %missing_neighbors
        end %missing_nodes_all_neighbors
    end % if getting  missingNodesInput
    

    %remove the missing nodes from the matrix (missing nodes MUST be sorted in descending order!!
    %so that removing one does not affect the index of the others)
    for j = 1:size(missing_nodes,2)
        missing_node_idx = missing_nodes(j);
        %remove column
        data(:, missing_node_idx) = [];
        %remove row
        data(missing_node_idx, :) = [];
        attData(missing_node_idx, :) = [];
    end

end %function RemoveRandomNodes3

%sigal - move old implementation to function
function [missing_nodes] = ChooseMissingNodes(num_nodes_to_remove, data, attData, totalAttNum, numAttPerPH, missing_nodes_mapping)
    missing_nodes_all_neighbors = zeros(1, size(data,2));
    
    %randomize a list of nodes to remove and sort it
    if size(missing_nodes_mapping,1)> 0
        missing_nodes = sort(missing_nodes_mapping(1,:) , 'descend');
        %find all missing node neighbors
        for curr_missing_node = missing_nodes
            missing_nodes_all_neighbors = missing_nodes_all_neighbors | data(curr_missing_node,:);
            missing_nodes_all_neighbors(1,curr_missing_node)=1;
        end
    else
        missing_nodes = [];
    end

    % outlier1 - nodes with only one edge
    numEdges = sum(data,1);
    invalidNodes1a = (numEdges==1); %%numEdges<3); %%(numEdges==1);
    missing_nodes_all_neighbors(1,invalidNodes1a) = 1;
    %invalidNodes1b = (numEdges>7); %% 6.13 (mem issues) use 7
    %invalidNodes1b = (numEdges>15); %%25); %%(numEdges==1); %% sigal - 6.2.13 max=15 (sarit)
    invalidNodes1b = (numEdges>8); %%15); %% sigal/sarit - 9.12.13 max=8
    missing_nodes_all_neighbors(1,invalidNodes1b) = 1;
    % outlier2 - nodes with less than numAttPerPH attributes
    numAttr = sum(attData,2)';
    invalidNodes2 = (numAttr<numAttPerPH);
    missing_nodes_all_neighbors(1,invalidNodes2) = 1;
    % outlier statistics
    count = nnz(invalidNodes1a|invalidNodes1b|invalidNodes2);
    if count*1.5 > size(data,2)
        fprintf('RemoveRandomNodes2: too many outliers nodes %d.\n',count);
    end
    
   for i=1:num_nodes_to_remove
        valid_nodes = find(missing_nodes_all_neighbors~=1);
		inx = ceil(rand(1)*size(valid_nodes,2));
        node = valid_nodes(inx);
        % add selected node to missing_nodes list and update the all neighbors list
        missing_nodes = [missing_nodes node];
        missing_nodes_all_neighbors(1,node)=1;
        missing_nodes_all_neighbors = missing_nodes_all_neighbors | data(node,:);
   end
    
end %ChooseMissingNodes


% sigal - append col & row for the placeholder
function [data] = ExpandDataByOne(data, friend, non_neighbors_distance)
    new_col = ones(size(data, 1), 1) * non_neighbors_distance;
    new_col(friend) = 1;
    data = [data new_col];
    new_row =  ones(1,size(data, 2)) * non_neighbors_distance;
    new_row(friend) = 1;
    data = [data; new_row];
    data(size(data, 1), size(data,2)) = 0;
end %ExpandDataByOne

% sigal - append row for the placeholder
function [attData] = ExpandAttByOne(attData, orgNode, non_neighbors_distance, totalAttNum, numAttPerPH)
    if totalAttNum>0 && numAttPerPH>0
        attIndices = find(attData(orgNode, :)==1);
        while size(attIndices,2) > numAttPerPH
            inx = ceil(rand(1)*size(attIndices,2));
            attIndices(:,inx) = [];
        end
    else
        attIndices=[];
    end
    new_row =  ones(1,size(attData, 2)) * non_neighbors_distance;
    for i=1:size(attIndices,2)
        new_row(i)=1;
    end
    attData = [attData; new_row];
end %ExpandAttByOne


