diff --git a/matlab/trust_region.m b/matlab/trust_region.m
new file mode 100644
index 0000000000000000000000000000000000000000..1edb87732c000b535ed78715082555aba0d73640
--- /dev/null
+++ b/matlab/trust_region.m
@@ -0,0 +1,245 @@
+function [x,check] = trust_region(fcn,x0,j1,j2,jacobian_flag,gstep,tolf,tolx,maxiter,debug,varargin)
+% Solves systems of non linear equations of several variables, using a
+% trust-region method.
+%
+% INPUTS
+%    fcn:             name of the function to be solved
+%    x0:              guess values
+%    j1:              equations index for which the model is solved
+%    j2:              unknown variables index
+%    jacobian_flag=1: jacobian given by the 'func' function
+%    jacobian_flag=0: jacobian obtained numerically
+%    gstep            increment multiplier in numercial derivative
+%                     computation
+%    tolf             tolerance for residuals
+%    tolx             tolerance for solution variation
+%    maxiter          maximum number of iterations
+%    debug            debug flag
+%    varargin:        list of arguments following bad_cond_flag
+%
+% OUTPUTS
+%    x:               results
+%    check=1:         the model can not be solved
+%
+% SPECIAL REQUIREMENTS
+%    none
+
+% Copyright (C) 2008-2012 VZLU Prague, a.s.
+% Copyright (C) 2014 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/>.
+%
+% Initial author: Jaroslav Hajek <highegg@gmail.com>, for GNU Octave
+
+if (ischar (fcn))
+    fcn = str2func (fcn);
+end
+
+n = length(j1);
+
+% These defaults are rather stringent. I think that normally, user
+% prefers accuracy to performance.
+
+macheps = eps (class (x0));
+
+niter = 1;
+
+x = x0;
+info = 0;
+
+% Initial evaluation.
+% Handle arbitrary shapes of x and f and remember them.
+fvec = fcn (x, varargin{:});
+fvec = fvec(j1);
+fn = norm (fvec);
+jcn = nan(n, 1);
+
+% Outer loop.
+while (niter < maxiter && ~info)
+
+    % Calculate function value and Jacobian (possibly via FD).
+    if jacobian_flag
+        [fvec, fjac] = fcn (x, varargin{:});
+        fvec = fvec(j1);
+        fjac = fjac(j1,j2);
+    else
+        dh = max(abs(x(j2)),gstep(1)*ones(n,1))*eps^(1/3);
+
+        for j = 1:n
+            xdh = x ;
+            xdh(j2(j)) = xdh(j2(j))+dh(j) ;
+            t = fcn(xdh,varargin{:});
+            fjac(:,j) = (t(j1) - fvec)./dh(j) ;
+            g(j) = fvec'*fjac(:,j) ;
+        end
+    end
+
+    % Get column norms, use them as scaling factors.
+    for j = 1:n
+        jcn(j) = norm(fjac(:,j));
+    end
+    if (niter == 1)
+        dg = jcn;
+        dg(dg == 0) = 1;
+    else
+        % Rescale adaptively.
+        % FIXME: the original minpack used the following rescaling strategy:
+        %   dg = max (dg, jcn);
+        % but it seems not good if we start with a bad guess yielding Jacobian
+        % columns with large norms that later decrease, because the corresponding
+        % variable will still be overscaled. So instead, we only give the old
+        % scaling a small momentum, but do not honor it.
+
+        dg = max (0.1*dg, jcn);
+    end
+
+    if (niter == 1)
+        xn = norm (dg .* x(j2));
+        % FIXME: something better?
+        delta = max (xn, 1);
+    end
+
+    % Get trust-region model (dogleg) minimizer.
+    s = - dogleg (fjac, fvec, dg, delta);
+    w = fvec + fjac * s;
+
+    sn = norm (dg .* s);
+    if (niter == 1)
+        delta = min (delta, sn);
+    end
+
+    x2 = x;
+    x2(j2) = x2(j2) + s;
+    fvec1 = fcn (x2, varargin{:});
+    fvec1 = fvec1(j1);
+    fn1 = norm (fvec1);
+
+    if (fn1 < fn)
+        % Scaled actual reduction.
+        actred = 1 - (fn1/fn)^2;
+    else
+        actred = -1;
+    end
+
+    % Scaled predicted reduction, and ratio.
+    t = norm (w);
+    if (t < fn)
+        prered = 1 - (t/fn)^2;
+        ratio = actred / prered;
+    else
+        prered = 0;
+        ratio = 0;
+    end
+
+    % Update delta.
+    if (ratio < 0.1)
+        delta = 0.5*delta;
+        if (delta <= 1e1*macheps*xn)
+            % Trust region became uselessly small.
+            info = -3;
+            break;
+        end
+    elseif (abs (1-ratio) <= 0.1)
+        delta = 1.4142*sn;
+    elseif (ratio >= 0.5)
+        delta = max (delta, 1.4142*sn);
+    end
+
+    if (ratio >= 1e-4)
+        % Successful iteration.
+        x(j2) = x(j2) + s;
+        xn = norm (dg .* x(j2));
+        fvec = fvec1;
+        fn = fn1;
+    end
+
+    niter = niter + 1;
+
+
+    % Tests for termination conditions. A mysterious place, anything
+    % can happen if you change something here...
+
+    % The rule of thumb (which I'm not sure M*b is quite following)
+    % is that for a tolerance that depends on scaling, only 0 makes
+    % sense as a default value. But 0 usually means uselessly long
+    % iterations, so we need scaling-independent tolerances wherever
+    % possible.
+
+    % FIXME -- why tolf*n*xn? If abs (e) ~ abs(x) * eps is a vector
+    % of perturbations of x, then norm (fjac*e) <= eps*n*xn, i.e. by
+    % tolf ~ eps we demand as much accuracy as we can expect.
+    disp([niter fn ratio])
+    if (fn <= tolf*n*xn)
+        info = 1;
+        % The following tests done only after successful step.
+    elseif (ratio >= 1e-4)
+        % This one is classic. Note that we use scaled variables again,
+        % but compare to scaled step, so nothing bad.
+        if (sn <= tolx*xn)
+            info = 2;
+            % Again a classic one. It seems weird to use the same tolf
+            % for two different tests, but that's what M*b manual appears
+            % to say.
+        elseif (actred < tolf)
+            info = 3;
+        end
+    end
+end
+
+check = ~info;
+end
+
+
+% Solve the double dogleg trust-region least-squares problem:
+% Minimize norm(r*x-b) subject to the constraint norm(d.*x) <= delta,
+% x being a convex combination of the gauss-newton and scaled gradient.
+
+% TODO: error checks
+% TODO: handle singularity, or leave it up to mldivide?
+
+function x = dogleg (r, b, d, delta)
+% Get Gauss-Newton direction.
+x = r \ b;
+xn = norm (d .* x);
+if (xn > delta)
+    % GN is too big, get scaled gradient.
+    s = (r' * b) ./ d;
+    sn = norm (s);
+    if (sn > 0)
+        % Normalize and rescale.
+        s = (s / sn) ./ d;
+        % Get the line minimizer in s direction.
+        tn = norm (r*s);
+        snm = (sn / tn) / tn;
+        if (snm < delta)
+            % Get the dogleg path minimizer.
+            bn = norm (b);
+            dxn = delta/xn; snmd = snm/delta;
+            t = (bn/sn) * (bn/xn) * snmd;
+            t = t - dxn * snmd^2 + sqrt ((t-dxn)^2 + (1-dxn^2)*(1-snmd^2));
+            alpha = dxn*(1-snmd^2) / t;
+        else
+            alpha = 0;
+        end
+    else
+        alpha = delta / xn;
+        snm = 0;
+    end
+    % Form the appropriate convex combination.
+    x = alpha * x + ((1-alpha) * min (snm, delta)) * s;
+end
+end
+