diff --git a/matlab/method_of_moments/method_of_moments.m b/matlab/method_of_moments/method_of_moments.m
index e4f3a3ffb2992efb3c077428ec640088d3d02bc8..eb5579f43a694597103effa5999d678cee2270df 100644
--- a/matlab/method_of_moments/method_of_moments.m
+++ b/matlab/method_of_moments/method_of_moments.m
@@ -91,7 +91,6 @@ function [oo_, options_mom_, M_] = method_of_moments(bayestopt_, options_, oo_,
 % - [ ] add option to use autocorrelations (we have useautocorr in identification toolbox already)
 % - [ ] SMM with extended path
 % - [ ] deal with measurement errors (once @wmutschl has implemented this in identification toolbox)
-% - [ ] improve check for duplicate moments by using the cellfun and unique functions
 % - [ ] dirname option to save output to different directory not yet implemented
 
 % The TeX option crashes MATLAB R2014a run with "-nodisplay" option
@@ -384,85 +383,66 @@ for i=1:options_mom_.obs_nbr
 end
 
 % -------------------------------------------------------------------------
-% Step 2: Checks and transformations for matched moments structure (preliminary)
+% Step 2: Checks and transformations for matched_moments structure
 % -------------------------------------------------------------------------
+M_.matched_moments_orig = M_.matched_moments; %save original structure
 
-% Initialize indices
-options_mom_.mom.index.E_y       = false(options_mom_.obs_nbr,1);                      %unconditional first order product moments
-options_mom_.mom.index.E_yy      = false(options_mom_.obs_nbr,options_mom_.obs_nbr);   %unconditional second order product moments
-options_mom_.mom.index.E_yyt     = false(options_mom_.obs_nbr,options_mom_.obs_nbr,0); %unconditional temporal second order product moments
-options_mom_.mom.index.E_y_pos   = zeros(options_mom_.obs_nbr,1);                      %position in matched moments block
-options_mom_.mom.index.E_yy_pos  = zeros(options_mom_.obs_nbr,options_mom_.obs_nbr);   %position in matched moments block
-options_mom_.mom.index.E_yyt_pos = zeros(options_mom_.obs_nbr,options_mom_.obs_nbr,0); %position in matched moments block
+% higher-order product moments not supported yet for GMM
+if strcmp(options_mom_.mom.mom_method, 'GMM') && any(cellfun(@sum,M_.matched_moments(:,3))> 2)
+    error('method_of_moments: GMM does not yet support product moments higher than 2. Change row %d in ''matched_moments'' block.',jm);
+end
 
+% check for duplicate moment conditions
 for jm=1:size(M_.matched_moments,1)
-    % higher-order product moments not supported yet for GMM
-    if strcmp(options_mom_.mom.mom_method, 'GMM') && sum(M_.matched_moments{jm,3}) > 2
-        error('method_of_moments: GMM does not yet support product moments higher than 2. Change row %d in ''matched_moments'' block.',jm);
-    end
-    % Check if declared variables are also observed (needed as otherwise the dataset variables won't coincide)
-    if any(~ismember(oo_.dr.inv_order_var(M_.matched_moments{jm,1})', oo_.dr.obs_var))
-        error('method_of_moments: Variables in row %d in ''matched_moments'' block need to be declared as VAROBS.', jm)
-    end
-    
-    if strcmp(options_mom_.mom.mom_method, 'GMM')
-    % Check (for now) that only lags are declared
-        if any(M_.matched_moments{jm,2}>0)
-            error('method_of_moments: Leads in row %d in the ''matched_moments'' block are not supported for GMM, shift the moments and declare only lags.', jm)
-        end
-        % Check (for now) that first declared variable has zero lag
-        if M_.matched_moments{jm,2}(1)~=0
-            error('method_of_moments: The first variable declared in row %d in the ''matched_moments'' block is not allowed to have a lead or lag for GMM;\n                   reorder the variables in the row such that the first variable has zero lag!',jm)
-        end
-    end
-    vars = oo_.dr.inv_order_var(M_.matched_moments{jm,1})';
-    if sum(M_.matched_moments{jm,3}) == 1
-        % First-order product moment
-        vpos = (oo_.dr.obs_var == vars);
-        options_mom_.mom.index.E_y(vpos,1) = true;
-        options_mom_.mom.index.E_y_pos(vpos,1) = jm;
-        M_.matched_moments{jm,4}=['E(',M_.endo_names{M_.matched_moments{jm,1}},')'];
-        M_.matched_moments{jm,5}=['$E(',M_.endo_names_tex{M_.matched_moments{jm,1}},')$'];
-    elseif sum(M_.matched_moments{jm,3}) == 2
-        % Second-order product moment
-        idx1 = (oo_.dr.obs_var == vars(1));
-        idx2 = (oo_.dr.obs_var == vars(2));
-        lag1 = M_.matched_moments{jm,2}(1);
-        lag2 = M_.matched_moments{jm,2}(2);
-        if lag1==0 && lag2==0 % contemporaneous covariance matrix
-            options_mom_.mom.index.E_yy(idx1,idx2) = true;
-            options_mom_.mom.index.E_yy(idx2,idx1) = true;
-            options_mom_.mom.index.E_yy_pos(idx1,idx2) = jm;
-            options_mom_.mom.index.E_yy_pos(idx2,idx1) = jm;
-            M_.matched_moments{jm,4}=['E(',M_.endo_names{M_.matched_moments{jm,1}(1)},',',M_.endo_names{M_.matched_moments{jm,1}(2)},')'];
-            M_.matched_moments{jm,5}=['$E({',M_.endo_names_tex{M_.matched_moments{jm,1}(1)},'}_t,{',M_.endo_names_tex{M_.matched_moments{jm,1}(1)},'}_t)$'];
-        elseif lag1==0 && lag2 < 0
-            options_mom_.mom.index.E_yyt(idx1,idx2,-lag2) = true;
-            options_mom_.mom.index.E_yyt_pos(idx1,idx2,-lag2) = jm;
-            M_.matched_moments{jm,4}=['E(',M_.endo_names{M_.matched_moments{jm,1}(1)},',',M_.endo_names{M_.matched_moments{jm,1}(2)},'(',num2str(lag2),'))'];
-            M_.matched_moments{jm,5}=['$E({',M_.endo_names_tex{M_.matched_moments{jm,1}(1)},'}_t\times{',M_.endo_names_tex{M_.matched_moments{jm,1}(1)},'_{t',num2str(lag2) ,'})$'];
+    % expand powers to vector of ones
+    if any(M_.matched_moments{jm,3}>1)
+        tmp1=[]; tmp2=[]; tmp3=[];
+        for jjm=1:length(M_.matched_moments{jm,3})
+            tmp1 = [tmp1 repmat(M_.matched_moments{jm,1}(jjm),[1 M_.matched_moments{jm,3}(jjm)]) ];
+            tmp2 = [tmp2 repmat(M_.matched_moments{jm,2}(jjm),[1 M_.matched_moments{jm,3}(jjm)]) ];
+            tmp3 = [tmp3 repmat(1,[1 M_.matched_moments{jm,3}(jjm)]) ];
         end
+        M_.matched_moments{jm,1} = tmp1;
+        M_.matched_moments{jm,2} = tmp2;
+        M_.matched_moments{jm,3} = tmp3;
     end
+    % shift time structure to focus only on lags
+    M_.matched_moments{jm,2} = M_.matched_moments{jm,2} - max(M_.matched_moments{jm,2});
+    % sort such that t=0 variable comes first
+    [M_.matched_moments{jm,2},idx_sort] = sort(M_.matched_moments{jm,2},'descend');
+    M_.matched_moments{jm,1} = M_.matched_moments{jm,1}(idx_sort);
+    M_.matched_moments{jm,3} = M_.matched_moments{jm,3}(idx_sort);    
 end
 
-%Remove duplicate elements
-UniqueMomIdx = [nonzeros(options_mom_.mom.index.E_y_pos); nonzeros(tril(options_mom_.mom.index.E_yy_pos)); nonzeros(options_mom_.mom.index.E_yyt_pos)];
-DuplicateMoms = setdiff(1:size(M_.matched_moments,1),UniqueMomIdx);
-if ~isempty(DuplicateMoms)
-    fprintf('Found and removed duplicate declared moments in ''matched_moments'' block in rows: %s.\n',num2str(DuplicateMoms))
+% find duplicate rows in cell array by making groups according to powers as we can then use cell2mat for the unique function
+powers = cellfun(@sum,M_.matched_moments(:,3))';
+UniqueMomIdx = [];
+for jpow = unique(powers)
+    idx1 = find(powers==jpow);
+    [~,idx2] = unique(cell2mat(M_.matched_moments(idx1,:)),'rows');
+    UniqueMomIdx = [UniqueMomIdx idx1(idx2)];
 end
-%reorder M_.matched_moments to be compatible with options_mom_.mom.index
-M_.matched_moments = M_.matched_moments(UniqueMomIdx,:);
-if strcmp(options_mom_.mom.mom_method,'SMM')
-    options_mom_.mom=rmfield(options_mom_.mom,'index');
+
+% remove duplicate elements
+DuplicateMoms = setdiff(1:size(M_.matched_moments_orig,1),UniqueMomIdx);
+if ~isempty(DuplicateMoms)    
+    fprintf('Found and removed duplicate declared moments in ''matched_moments'' block in rows:\n %s.\n',num2str(DuplicateMoms))
+    fprintf('Dynare will continue with remaining moment conditions\n');
+end
+
+if strcmp(options_mom_.mom.mom_method, 'SMM')
+    % for SMM we can keep the original structure but get rid of duplicate moments
+    M_.matched_moments = M_.matched_moments_orig(sort(UniqueMomIdx),:);    
+elseif strcmp(options_mom_.mom.mom_method, 'GMM')
+    % for GMM we use the transformed matched_moments structure
+    M_.matched_moments = M_.matched_moments(sort(UniqueMomIdx),:);
 end
 
 % Check if both prefilter and first moments were specified
-options_mom_.mom.first_moment_indicator = find(cellfun(@(x) sum(abs(x))==1,M_.matched_moments(:,3)))';
-if options_mom_.prefilter && ~isempty(options_mom_.mom.first_moment_indicator)
-    fprintf('Centered moments requested (prefilter option is set); therefore, ignore declared first moments in ''matched_moments'' block in rows: %u.\n',options_mom_.mom.first_moment_indicator');
-    M_.matched_moments(options_mom_.mom.first_moment_indicator,:)=[]; %remove first moments entries
-    options_mom_.mom.first_moment_indicator = [];
+first_moment_indicator = find(cellfun(@(x) sum(abs(x))==1,M_.matched_moments(:,3)))';
+if options_mom_.prefilter && ~isempty(first_moment_indicator)
+    fprintf('Centered moments requested (prefilter option is set); therefore, ignore declared first moments in ''matched_moments'' block.\n');
+    M_.matched_moments(first_moment_indicator,:)=[]; %remove first moments entries    
 end
 options_mom_.mom.mom_nbr = size(M_.matched_moments,1);
 
@@ -972,15 +952,39 @@ end
 % -------------------------------------------------------------------------
 % Step 9: Display estimation results
 % -------------------------------------------------------------------------
-title = ['Data moments and model moments (',options_mom_.mom.mom_method,')'];
-headers = {'Moment','Data','Model','% dev. target'};
-labels= M_.matched_moments(:,4);
-data_mat=[oo_.mom.data_moments oo_.mom.model_moments 100*abs((oo_.mom.model_moments-oo_.mom.data_moments)./oo_.mom.data_moments)];
+title = ['Comparison of data moments and model moments (',options_mom_.mom.mom_method,')'];
+headers = {'Moment','Data','Model'};
+for jm = 1:size(M_.matched_moments,1)
+    lables_tmp = 'E[';
+    lables_tmp_tex = 'E \left[ ';
+    for jvar = 1:length(M_.matched_moments{jm,1})
+        lables_tmp = [lables_tmp M_.endo_names{M_.matched_moments{jm,1}(jvar)}];
+        lables_tmp_tex = [lables_tmp_tex, '{', M_.endo_names_tex{M_.matched_moments{jm,1}(jvar)}, '}'];
+        if M_.matched_moments{jm,2}(jvar) ~= 0
+            lables_tmp = [lables_tmp, '(', num2str(M_.matched_moments{jm,2}(jvar)), ')'];
+            lables_tmp_tex = [lables_tmp_tex, '_{t', num2str(M_.matched_moments{jm,2}(jvar)), '}'];
+        else
+            lables_tmp_tex = [lables_tmp_tex, '_{t}'];
+        end
+        if M_.matched_moments{jm,3}(jvar) > 1
+            lables_tmp = [lables_tmp, '^', num2str(M_.matched_moments{jm,3}(jvar))];
+            lables_tmp_tex = [lables_tmp_tex, '^{', num2str(M_.matched_moments{jm,3}(jvar)) '}'];
+        end
+        if jvar == length(M_.matched_moments{jm,1})
+            lables_tmp = [lables_tmp, ']'];
+            lables_tmp_tex = [lables_tmp_tex, ' \right]'];
+        else
+            lables_tmp = [lables_tmp, '*'];
+            lables_tmp_tex = [lables_tmp_tex, ' \times '];
+        end
+    end
+    labels{jm,1} = lables_tmp;
+    labels_TeX{jm,1} = lables_tmp_tex;
+end
+data_mat=[oo_.mom.data_moments oo_.mom.model_moments ];
 dyntable(options_mom_, title, headers, labels, data_mat, cellofchararraymaxlength(labels)+2, 10, 7);
-if options_mom_.TeX
-    lh = cellofchararraymaxlength(labels)+2;
-    labels_TeX = M_.matched_moments(:,5);
-    dyn_latex_table(M_, options_mom_, title, 'sim_corr_matrix', headers, labels_TeX, data_mat, lh, 10, 7);
+if options_mom_.TeX    
+    dyn_latex_table(M_, options_mom_, title, ['comparison_moments_', options_mom_.mom.mom_method], headers, labels_TeX, data_mat, cellofchararraymaxlength(labels)+2, 10, 7);
 end
 
 if options_mom_.mode_check.status
diff --git a/matlab/method_of_moments/method_of_moments_objective_function.m b/matlab/method_of_moments/method_of_moments_objective_function.m
index cb069ef1820b40aba1aad04a8c778f8ec9fffa5f..99b7d91aec04d9ae591d4f907a16e9489f8b532c 100644
--- a/matlab/method_of_moments/method_of_moments_objective_function.m
+++ b/matlab/method_of_moments/method_of_moments_objective_function.m
@@ -154,65 +154,55 @@ if strcmp(options_mom_.mom.mom_method,'GMM')
     end
     
     oo_.mom.model_moments = NaN(options_mom_.mom.mom_nbr,1);
-    offset = 0;
-    % First moments
-    if ~options_mom_.prefilter && isfield(options_mom_.mom.index,'E_y') && nnz(options_mom_.mom.index.E_y) > 0
-        E_y = pruned_state_space.E_y;
-        E_y_nbr = nnz(options_mom_.mom.index.E_y);
-        oo_.mom.model_moments(offset+1:E_y_nbr,1) = E_y(options_mom_.mom.index.E_y);
-        if options_mom_.mom.compute_derivs && ( options_mom_.mom.analytic_standard_errors || options_mom_.mom.analytic_jacobian )
-            oo_.mom.model_moments_params_derivs(offset+1:E_y_nbr,:) = pruned_state_space.dE_y(options_mom_.mom.index.E_y,:);
-        end
-        offset = offset + E_y_nbr;
-    end
-    % Second moments
-    % Contemporaneous covariance
-    if isfield(options_mom_.mom.index,'E_yy') && nnz(options_mom_.mom.index.E_yy) > 0
-        if options_mom_.prefilter
-            E_yy = pruned_state_space.Var_y;
-            if options_mom_.mom.compute_derivs && ( options_mom_.mom.analytic_standard_errors || options_mom_.mom.analytic_jacobian )
-                dE_yy = pruned_state_space.dVar_y;
-            end            
-        else
-            E_yy = pruned_state_space.Var_y + pruned_state_space.E_y*pruned_state_space.E_y';
+    for jm = 1:size(M_.matched_moments,1)
+        % First moments
+        if ~options_mom_.prefilter && (sum(M_.matched_moments{jm,3}) == 1)
+            idx1 = (oo_.dr.obs_var == find(oo_.dr.order_var==M_.matched_moments{jm,1}) );
+            oo_.mom.model_moments(jm,1) = pruned_state_space.E_y(idx1);
             if options_mom_.mom.compute_derivs && ( options_mom_.mom.analytic_standard_errors || options_mom_.mom.analytic_jacobian )
-                dE_yy = pruned_state_space.dVar_y;
-                for jp=1:totparam_nbr
-                    dE_yy(:,:,jp) = dE_yy(:,:,jp) + pruned_state_space.dE_y(:,jp)*pruned_state_space.E_y' + pruned_state_space.E_y*pruned_state_space.dE_y(:,jp)';
-                end
+                oo_.mom.model_moments_params_derivs(jm,:) = pruned_state_space.dE_y(idx1,:);
             end
         end
-        E_yy_nbr = nnz(tril(options_mom_.mom.index.E_yy));
-        oo_.mom.model_moments(offset+(1:E_yy_nbr),1) = E_yy(tril(options_mom_.mom.index.E_yy));
-        if options_mom_.mom.compute_derivs && ( options_mom_.mom.analytic_standard_errors || options_mom_.mom.analytic_jacobian )
-            oo_.mom.model_moments_params_derivs(offset+(1:E_yy_nbr),:) = reshape(dE_yy(repmat(tril(options_mom_.mom.index.E_yy),[1 1 totparam_nbr])),E_yy_nbr,totparam_nbr);
-        end
-        offset = offset + E_yy_nbr;
-    end
-    % Lead/lags covariance
-    if isfield(options_mom_.mom.index,'E_yyt') && nnz(options_mom_.mom.index.E_yyt) > 0
-        if options_mom_.prefilter
-            E_yyt = pruned_state_space.Var_yi;
-            if options_mom_.mom.compute_derivs && ( options_mom_.mom.analytic_standard_errors || options_mom_.mom.analytic_jacobian )
-                dE_yyt = pruned_state_space.dVar_yi;
-            end
-        else
-            E_yyt = pruned_state_space.Var_yi + repmat(pruned_state_space.E_y*pruned_state_space.E_y',[1 1 size(pruned_state_space.Var_yi,3)]);
-            if options_mom_.mom.compute_derivs && ( options_mom_.mom.analytic_standard_errors || options_mom_.mom.analytic_jacobian )
-                dE_yyt = pruned_state_space.dVar_yi;
-                for jp=1:totparam_nbr
-                    dE_yyt(:,:,:,jp) = dE_yyt(:,:,:,jp) + repmat(pruned_state_space.dE_y(:,jp)*pruned_state_space.E_y',[1 1 size(pruned_state_space.Var_yi,3)])...
-                                                        + repmat(pruned_state_space.E_y*pruned_state_space.dE_y(:,jp)',[1 1 size(pruned_state_space.Var_yi,3)]);
-                end
+        % Second moments
+        if (sum(M_.matched_moments{jm,3}) == 2)
+            idx1 = (oo_.dr.obs_var == find(oo_.dr.order_var==M_.matched_moments{jm,1}(1)) );
+            idx2 = (oo_.dr.obs_var == find(oo_.dr.order_var==M_.matched_moments{jm,1}(2)) );
+            if nnz(M_.matched_moments{jm,2}) == 0
+                % Covariance
+                if options_mom_.prefilter
+                    oo_.mom.model_moments(jm,1) = pruned_state_space.Var_y(idx1,idx2);
+                    if options_mom_.mom.compute_derivs && ( options_mom_.mom.analytic_standard_errors || options_mom_.mom.analytic_jacobian )
+                        oo_.mom.model_moments_params_derivs(jm,:) = pruned_state_space.dVar_y(idx1,idx2,:);
+                    end
+                else
+                    oo_.mom.model_moments(jm,1) = pruned_state_space.Var_y(idx1,idx2) + pruned_state_space.E_y(idx1)*pruned_state_space.E_y(idx2)';
+                    if options_mom_.mom.compute_derivs && ( options_mom_.mom.analytic_standard_errors || options_mom_.mom.analytic_jacobian )
+                        for jp=1:totparam_nbr
+                            oo_.mom.model_moments_params_derivs(jm,jp) = pruned_state_space.dVar_y(idx1,idx2,jp) + pruned_state_space.dE_y(idx1,jp)*pruned_state_space.E_y(idx2)' + pruned_state_space.E_y(idx1)*pruned_state_space.dE_y(idx2,jp)';
+                        end
+                    end
+                end            
+            else
+                % Autocovariance
+                lag = -M_.matched_moments{jm,2}(2); %note that leads/lags in matched_moments are transformed such that first entry is always 0 and the second is a lag
+                if options_mom_.prefilter
+                    oo_.mom.model_moments(jm,1) = pruned_state_space.Var_yi(idx1,idx2,lag);
+                    if options_mom_.mom.compute_derivs && ( options_mom_.mom.analytic_standard_errors || options_mom_.mom.analytic_jacobian )
+                        oo_.mom.model_moments_params_derivs(jm,:) = pruned_state_space.dVar_yi(idx1,idx2,lag,:);
+                    end
+                else
+                    oo_.mom.model_moments(jm,1) = pruned_state_space.Var_yi(idx1,idx2,lag) + pruned_state_space.E_y(idx1)*pruned_state_space.E_y(idx2)';
+                    if options_mom_.mom.compute_derivs && ( options_mom_.mom.analytic_standard_errors || options_mom_.mom.analytic_jacobian )
+                        for jp=1:totparam_nbr
+                            oo_.mom.model_moments_params_derivs(jm,jp) = vec( pruned_state_space.dVar_yi(idx1,idx2,lag,jp) + pruned_state_space.dE_y(idx1,jp)*pruned_state_space.E_y(idx2)' + pruned_state_space.E_y(idx1)*pruned_state_space.dE_y(idx2,jp)');
+                        end
+                    end
+                end            
             end
-        end
-        E_yyt_nbr = nnz(options_mom_.mom.index.E_yyt);
-        oo_.mom.model_moments(offset+(1:E_yyt_nbr),1) = E_yyt(options_mom_.mom.index.E_yyt);
-        if options_mom_.mom.compute_derivs && ( options_mom_.mom.analytic_standard_errors || options_mom_.mom.analytic_jacobian )
-            oo_.mom.model_moments_params_derivs(offset+(1:E_yyt_nbr),:) = reshape(dE_yyt(repmat(options_mom_.mom.index.E_yyt,[1 1 1 totparam_nbr])),E_yyt_nbr,totparam_nbr);
-        end
+        end        
     end
-
+    
+    
 elseif strcmp(options_mom_.mom.mom_method,'SMM')
     %------------------------------------------------------------------------------
     % 3. Compute Moments of the model solution for normal innovations