function [codes,soft_idx] = lasc_encode(descrs, encoder)
% [codes,soft_idx] = lasc_encode(descrs, encoder)
% perform the LASC algorithm on all descriptors. 
% 
%        codes: structural body with first- and second-order LASC code matrix of 
%               the descriptors. Each of them is LxN which N is #descriptors.
%     soft_idx: actived indices of atoms in the dictionary, Nx(knn) in size.
%       descrs: descriptors of an image(e.g. SIFT descriptors in our case), DxN.
%      encoder: dictionary which calculated by 'trainEncoder.m'.
% 
% For efficiency, default proximity measure is d_s;

% -------------------------------------------------------------------------
% For theoretical and technical details, please refer to the following paper:
%
% Peihua Li, Xiaoxiao Lu, Qilong Wang, "From Dictionary of Visual 
% Words to Subspaces: Locality-constrained Affine Subspace Coding", CVPR 2015.
%
% Please cite the paper above if you use the code.
% For questions, please contact: Xiaoxiao Lu (Email: shaw@mail.dlut.edu.cn)
%                                Qilong Wang (Email: wangqilong.415@163.com)
%                                Peihua Li   (Email: peihuali at dlut dot edu dot cn)
% -------------------------------------------------------------------------

% calculate proximity measure according to d_s %
knn = 3;
dist_matrix = sp_dist2(descrs', encoder.words');
[dist2,min_ind] = sort(dist_matrix,2, 'ascend');
soft_idx = min_ind(:,1:knn);
dist2 = dist2(:,1:knn);
beta = 50;
weight = ones(size(dist2))./(1+exp(beta*dist2));    %lambda = 1;
weight = bsxfun(@rdivide, weight, sum(weight,2));
weight(isnan(weight)) = 0;

% encoding features using soft assignment %
cum_pcaNum = cumsum(encoder.pca.pcaNum);
cum_pcaNum = [ 0; cum_pcaNum ];
codes.first = single(zeros(cum_pcaNum(end), size(descrs, 2)));
codes.second = single(zeros(cum_pcaNum(end), size(descrs, 2)));
for i = 1:encoder.numWords       
    curr_idx = find(soft_idx == i);
    curr_weight = weight(curr_idx);
    curr_idx = mod(curr_idx,size(descrs, 2));
    curr_idx (curr_idx == 0) = size(descrs, 2);
    curr_num = length(curr_idx);   
    if curr_num > 0
       beta = encoder.pca.proj{i} * bsxfun(@minus, descrs(:,curr_idx), encoder.words(:,i));
       weight_soft = repmat(curr_weight,1,encoder.pca.pcaNum(i))';      
       codes.first(cum_pcaNum(i)+1:cum_pcaNum(i+1), curr_idx) = beta.* weight_soft;
       codes.second(cum_pcaNum(i)+1:cum_pcaNum(i+1), curr_idx) = (beta.^2 -1).* weight_soft;  
    end
end
