function [ys,params,info] = evaluate_steady_state(ys_init,M,options,oo,steadystate_check_flag)
% function [ys,params,info] = evaluate_steady_state(ys_init,M,options,oo,steadystate_check_flag)
% Computes the steady state
%
% INPUTS
%   ys_init                   vector           initial values used to compute the steady
%                                                 state
%   M                         struct           model structure
%   options                   struct           options
%   oo                        struct           output results
%   steadystate_check_flag    boolean          if true, check that the
%                                              steadystate verifies the
%                                              static model
%
% OUTPUTS
%   ys                        vector           steady state
%   params                    vector           model parameters possibly
%                                              modified by user steadystate
%                                              function
%   info                      2x1 vector       error codes
%
% SPECIAL REQUIREMENTS
%   none

% Copyright (C) 2001-2013 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare.  If not, see <http://www.gnu.org/licenses/>.

    info = 0;
    check = 0;

    steadystate_flag = options.steadystate_flag;
    params = M.params;
    exo_ss = [oo.exo_steady_state; oo.exo_det_steady_state];

    if length(M.aux_vars) > 0
        h_set_auxiliary_variables = str2func([M.fname '_set_auxiliary_variables']);
        ys_init = h_set_auxiliary_variables(ys_init,exo_ss,M.params);
    end

    if options.ramsey_policy
        if steadystate_flag
            % explicit steady state file
            [ys,params,info] = evaluate_steady_state_file(ys_init,exo_ss,M, ...
                                                           options);
            %test whether it solves model conditional on the instruments
            [resids] = evaluate_static_model(ys,exo_ss,params,M,options); 
            n_multipliers=M.endo_nbr-M.orig_endo_nbr;
            nan_indices=find(isnan(resids(n_multipliers+1:end)));

            if ~isempty(nan_indices)
                fprintf('\nevaluate_steady_state: The steady state file computation for the Ramsey problem resulted in NaNs.\n')
                fprintf('evaluate_steady_state: The steady state was computed conditional on the following initial instrument values: \n') 
                for ii = 1:size(options.instruments,1);
                    fprintf('\t %s \t %f \n',options.instruments(ii,:),ys_init(strmatch(options.instruments(ii,:),M.endo_names,'exact')))
                end
                fprintf('evaluate_steady_state: The problem occured in the following equations: \n')
                fprintf('\t Equation(s): ')
                for ii=1:length(nan_indices)
                        fprintf('%d, ',nan_indices(ii));
                end
                skipline();
                fprintf('evaluate_steady_state: If those initial values are not admissable, change them using an initval-block.\n') 
                skipline(2);
                check=1;
                info(1) = 84;
                info(2) = resids'*resids;           
                return;
            end
            if max(abs(resids(n_multipliers+1:end))) > options.dynatol.f %does it solve for all variables except for the Lagrange multipliers
                fprintf('\nevaluate_steady_state: The steady state file does not solve the steady state for the Ramsey problem.\n')
                fprintf('evaluate_steady_state: Conditional on the following instrument values: \n') 
                for ii = 1:size(options.instruments,1);
                    fprintf('\t %s \t %f \n',options.instruments(ii,:),ys_init(strmatch(options.instruments(ii,:),M.endo_names,'exact')))
                end
                fprintf('evaluate_steady_state: the following equations have non-zero residuals: \n')                
                for ii=n_multipliers+1:M.endo_nbr
                    if abs(resids(ii)) > options.dynatol.f/100
                        fprintf('\t Equation number %d: %f\n',ii-n_multipliers, resids(ii))
                    end
                end
                skipline(2);
                info(1) = 85;
                info(2) = resids'*resids;           
                return;
            end
        end
        %either if no steady state file or steady state file without problems
        [ys,params,info] = dyn_ramsey_static(ys_init,M,options,oo);
        if info
           info=81;%case should not happen
           return;
        end
        %check whether steady state really solves the model 
        [resids] = evaluate_static_model(ys,exo_ss,params,M,options); 

        n_multipliers=M.endo_nbr-M.orig_endo_nbr;
        nan_indices_multiplier=find(isnan(resids(1:n_multipliers)));
        nan_indices=find(isnan(resids(n_multipliers+1:end)));

        if ~isempty(nan_indices)
            fprintf('\nevaluate_steady_state: The steady state computation for the Ramsey problem resulted in NaNs.\n')
            fprintf('evaluate_steady_state: The steady state computation resulted in the following instrument values: \n') 
            for i = 1:size(options.instruments,1);
                fprintf('\t %s \t %f \n',options.instruments(i,:),ys(strmatch(options.instruments(i,:),M.endo_names,'exact')))
            end
            fprintf('evaluate_steady_state: The problem occured in the following equations: \n')
            fprintf('\t Equation(s): ')
            for ii=1:length(nan_indices)
                    fprintf('%d, ',nan_indices(ii));
            end
            skipline();
            info(1) = 82;
            return;
        end

        if ~isempty(nan_indices_multiplier)
            fprintf('\nevaluate_steady_state: The steady state computation for the Ramsey problem resulted in NaNs in the auxiliary equations.\n')
            fprintf('evaluate_steady_state: The steady state computation resulted in the following instrument values: \n') 
            for i = 1:size(options.instruments,1);
                fprintf('\t %s \t %f \n',options.instruments(i,:),ys(strmatch(options.instruments(i,:),M.endo_names,'exact')))
            end
            fprintf('evaluate_steady_state: The problem occured in the following equations: \n')
            fprintf('\t Auxiliary equation(s): ')
            for ii=1:length(nan_indices_multiplier)
                    fprintf('%d, ',nan_indices_multiplier(ii));
            end
            skipline();
            info(1) = 83;
            return;
        end

        if max(abs(resids)) > options.dynatol.f %does it solve for all variables including the auxiliary ones
            fprintf('\nevaluate_steady_state: The steady state for the Ramsey problem could not be computed.\n')
            fprintf('evaluate_steady_state: The steady state computation stopped with the following instrument values:: \n') 
            for i = 1:size(options.instruments,1);
                fprintf('\t %s \t %f \n',options.instruments(i,:),ys_init(strmatch(options.instruments(i,:),M.endo_names,'exact')))
            end
            fprintf('evaluate_steady_state: The following equations have non-zero residuals: \n')                
            for ii=1:n_multipliers
                if abs(resids(ii)) > options.dynatol.f/100
                    fprintf('\t Auxiliary Ramsey equation number %d: %f\n',ii, resids(ii))
                end
            end
            for ii=n_multipliers+1:M.endo_nbr
                if abs(resids(ii)) > options.dynatol.f/100
                    fprintf('\t Equation number %d: %f\n',ii-n_multipliers, resids(ii))
                end
            end
            skipline(2);
            info(1) = 81;
            info(2) = resids'*resids;           
            return;
        end       
    elseif steadystate_flag
        % explicit steady state file
        [ys,params,info] = evaluate_steady_state_file(ys_init,exo_ss,M, ...
                                                       options);
        if info(1)
            return;
        end
    elseif (options.bytecode == 0 && options.block == 0)
        if options.linear == 0
            % non linear model
            [ys,check] = dynare_solve([M.fname '_static'],...
                                      ys_init,...
                                      options.jacobian_flag, ...
                                      exo_ss, params);
        else
            % linear model
            fh_static = str2func([M.fname '_static']);
            [fvec,jacob] = fh_static(ys_init,exo_ss, ...
                                     params);

            ii = find(~isfinite(fvec));
            if ~isempty(ii)
                ys=fvec;
                check=1;
                disp(['STEADY:  numerical initial values or parameters incompatible with the following' ...
                      ' equations'])
                disp(ii')
                disp('Check whether your model in truly linear')
            elseif isempty(ii) && max(abs(fvec)) > 1e-12
                ys = ys_init-jacob\fvec;
            else
                ys = ys_init;
            end
            if options.debug
                if any(any(isinf(jacob) | isnan(jacob)))
                    [infrow,infcol]=find(isinf(jacob) | isnan(jacob));
                    fprintf('\nSTEADY:  The Jacobian contains Inf or NaN. The problem arises from: \n\n')
                    for ii=1:length(infrow)
                        if infcol(ii)<=M.orig_endo_nbr
                            fprintf('STEADY:  Derivative of Equation %d with respect to Variable %s  (initial value of %s: %g) \n',infrow(ii),deblank(M.endo_names(infcol(ii),:)),deblank(M.endo_names(infcol(ii),:)),ys_init(infcol(ii)))
                        else %auxiliary vars
                            orig_var_index=M.aux_vars(1,infcol(ii)-M.orig_endo_nbr).orig_index;
                            fprintf('STEADY:  Derivative of Equation %d with respect to Variable %s  (initial value of %s: %g) \n',infrow(ii),deblank(M.endo_names(orig_var_index,:)),deblank(M.endo_names(orig_var_index,:)),ys_init(infcol(ii)))            
                        end
                    end
                    disp('STEADY: Check whether your model in truly linear\n')
                end            
            end
        end
    else
        % block or bytecode
        [ys,check] = dynare_solve_block_or_bytecode(ys_init,exo_ss, params, ...
                                                    options, M);
    end

    if check
        info(1)= 20;
        resid = evaluate_static_model(ys_init,exo_ss,params,M,options);
        info(2) = resid'*resid ;
        if isnan(info(2))
            info(1)=22;
        end
        return
    end

    % If some equations are tagged [static] or [dynamic], verify consistency
    if M.static_and_dynamic_models_differ
        % Evaluate residual of *dynamic* model using the steady state
        % computed on the *static* one
        z = repmat(ys,1,M.maximum_lead + M.maximum_lag + 1);
        zx = repmat([exo_ss'], M.maximum_lead + M.maximum_lag + 1, 1);
        if options.bytecode
            [chck, r, junk]= bytecode('dynamic','evaluate', z, zx, M.params, ys, 1);
            mexErrCheck('bytecode', chck);
        elseif options.block
            [r, oo.dr] = feval([M.fname '_dynamic'], z', zx, M.params, ys, M.maximum_lag+1, oo.dr);
        else
            iyv = M.lead_lag_incidence';
            iyr0 = find(iyv(:));
            xys = z(iyr0);
            r = feval([M.fname '_dynamic'], z(iyr0), zx, M.params, ys, M.maximum_lag + 1);
        end

        % Fail if residual greater than tolerance
        if max(abs(r)) > options.solve_tolf
            info(1) = 25;
            return
        end
    end
    
    if ~isreal(ys)
        info(1) = 21;
        info(2) = sum(imag(ys).^2);
        ys = real(ys);
        return
    end

    if ~isempty(find(isnan(ys)))
        info(1) = 22;
        info(2) = NaN;
        return
    end

    

