diff --git a/.gitignore b/.gitignore
index db2052d98b06c78cdd0e4cf674744c163d5eefb3..d5aefb1d2c00323f642f0756809e3b4444b85709 100644
--- a/.gitignore
+++ b/.gitignore
@@ -99,6 +99,12 @@ doc/internals/ltxpng
 /mex/build/matlab/*/*.mod
 /mex/build/octave/*/*.mod
 
+# Extra rules for trust_region MEX testfiles
+/mex/sources/block_trust_region/test/*.mod
+/mex/sources/block_trust_region/test/dulmage_mendelsohn_test
+/mex/sources/block_trust_region/test/trust_region_test
+!/mex/sources/block_trust_region/test/Makefile
+
 # Dynare++
 /dynare++/integ/src/quadrature-points.dSYM/
 /dynare++/src/dynare++.dSYM/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7b502354cc062ef2709f03fb6cc72de568b12fa4..65806de01fcb71354b840b0e85d3ec33cba5542b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -8,15 +8,15 @@ variables:
 # The next stanza creates the version number used for the source tarball and the
 # binary packages. Here are the following possible cases:
 # - if VERSION was already set (when manually running a pipeline), use it
-# - if we are in the official Dynare repository:
+# - if we are in the official Enterprise repository:
 #   + if on a tag: use the tag
-#   + if on master: use 4.7-unstable-$TIMESTAMP-$COMMIT
+#   + if on master: use enterprise-unstable-$TIMESTAMP-$COMMIT
 #   + on another branch: use $BRANCH-$TIMESTAMP-$COMMIT
 # - if in a personal repository: use $USER-$TIMESTAMP-$COMMIT
 before_script:
-  - '[[ -z $VERSION ]] && [[ $CI_PROJECT_NAMESPACE == Dynare ]] && [[ -n $CI_COMMIT_TAG ]] && export VERSION=$CI_COMMIT_TAG'
-  - '[[ -z $VERSION ]] && [[ $CI_PROJECT_NAMESPACE == Dynare ]] && [[ $CI_COMMIT_REF_NAME == master ]] && export VERSION=4.7-unstable-$(date +%F-%H%M)-$CI_COMMIT_SHORT_SHA'
-  - '[[ -z $VERSION ]] && [[ $CI_PROJECT_NAMESPACE == Dynare ]] && export VERSION=$CI_COMMIT_REF_NAME-$(date +%F-%H%M)-$CI_COMMIT_SHORT_SHA'
+  - '[[ -z $VERSION ]] && [[ $CI_PROJECT_NAMESPACE == Enterprise ]] && [[ -n $CI_COMMIT_TAG ]] && export VERSION=$CI_COMMIT_TAG'
+  - '[[ -z $VERSION ]] && [[ $CI_PROJECT_NAMESPACE == Enterprise ]] && [[ $CI_COMMIT_REF_NAME == enterprise ]] && export VERSION=enterprise-unstable-$(date +%F-%H%M)-$CI_COMMIT_SHORT_SHA'
+  - '[[ -z $VERSION ]] && [[ $CI_PROJECT_NAMESPACE == Enterprise ]] && export VERSION=$CI_COMMIT_REF_NAME-$(date +%F-%H%M)-$CI_COMMIT_SHORT_SHA'
   - '[[ -z $VERSION ]] && export VERSION=$CI_PROJECT_NAMESPACE-$(date +%F-%H%M)-$CI_COMMIT_SHORT_SHA'
 
 stages:
@@ -197,25 +197,31 @@ test_dynare++:
 # those jobs to start before the “test” and “pkg” stages have succeeded. Hence
 # we stick to the “dependencies” keyword.
 
-deploy_manual_unstable:
+deploy_snapshot_enterprise:
   stage: deploy
   rules:
-    - if: '$CI_PROJECT_NAMESPACE == "Dynare" && $CI_COMMIT_REF_NAME == "master"'
+    - if: '$CI_PROJECT_NAMESPACE == "Enterprise" && $CI_COMMIT_REF_NAME == "enterprise"'
       when: on_success
     - when: never
   tags:
     - restricted
   dependencies:
-    - build_doc
+    - pkg_source
+    - pkg_windows
+    - pkg_macOS
   script:
-    - rm -rf doc/manual/build/html/_static/mathjax
-    - ln -s /usr/share/javascript/mathjax doc/manual/build/html/_static/mathjax
-    - rsync --recursive --links --delete doc/manual/build/html/ /srv/www.dynare.org/manual-unstable/
+    - f=(windows/exe/*) && osslsigncode sign -pkcs12 ~/cepremap-comodo-sectigo-code-signing.p12 -n Dynare -i https://www.dynare.org -t http://timestamp.comodoca.com -in ${f[0]} -out ${f[0]}.signed && mv ${f[0]}.signed ${f[0]}
+    - cp *.tar.xz /srv/www.dynare.org/snapshot_ecb/source/ && ln -sf *.tar.xz /srv/www.dynare.org/snapshot_ecb/source/dynare-latest-src.tar.xz
+    - f=(windows/exe/*) && cp ${f[0]} /srv/www.dynare.org/snapshot_ecb/windows/ && ln -sf ${f[0]##*/} /srv/www.dynare.org/snapshot_ecb/windows/dynare-latest-win.exe
+    - f=(windows/7z/*) && cp ${f[0]} /srv/www.dynare.org/snapshot_ecb/windows-7z/ && ln -sf ${f[0]##*/} /srv/www.dynare.org/snapshot_ecb/windows-7z/dynare-latest-win.7z
+    - f=(windows/zip/*) && cp ${f[0]} /srv/www.dynare.org/snapshot_ecb/windows-zip/ && ln -sf ${f[0]##*/} /srv/www.dynare.org/snapshot_ecb/windows-zip/dynare-latest-win.zip
+    - f=(macOS/pkg/*) && cp ${f[0]} /srv/www.dynare.org/snapshot_ecb/macos/ && ln -sf ${f[0]##*/} /srv/www.dynare.org/snapshot_ecb/macos/dynare-latest-macos.pkg
+    - ~/update-snapshot_ecb-list.sh
 
-deploy_snapshot_unstable:
+deploy_release_enterprise:
   stage: deploy
   rules:
-    - if: '$CI_PROJECT_NAMESPACE == "Dynare" && $CI_COMMIT_REF_NAME == "master"'
+    - if: '$CI_PROJECT_NAMESPACE == "Enterprise" && $CI_COMMIT_TAG =~ /^enterprise-.*/'
       when: on_success
     - when: never
   tags:
@@ -226,10 +232,8 @@ deploy_snapshot_unstable:
     - pkg_macOS
   script:
     - f=(windows/exe/*) && osslsigncode sign -pkcs12 ~/cepremap-comodo-sectigo-code-signing.p12 -n Dynare -i https://www.dynare.org -t http://timestamp.comodoca.com -in ${f[0]} -out ${f[0]}.signed && mv ${f[0]}.signed ${f[0]}
-    - cp *.tar.xz /srv/www.dynare.org/snapshot/source/ && ln -sf *.tar.xz /srv/www.dynare.org/snapshot/source/dynare-latest-src.tar.xz
-    - f=(windows/exe/*) && cp ${f[0]} /srv/www.dynare.org/snapshot/windows/ && ln -sf ${f[0]##*/} /srv/www.dynare.org/snapshot/windows/dynare-latest-win.exe
-    - f=(windows/7z/*) && cp ${f[0]} /srv/www.dynare.org/snapshot/windows-7z/ && ln -sf ${f[0]##*/} /srv/www.dynare.org/snapshot/windows-7z/dynare-latest-win.7z
-    - f=(windows/zip/*) && cp ${f[0]} /srv/www.dynare.org/snapshot/windows-zip/ && ln -sf ${f[0]##*/} /srv/www.dynare.org/snapshot/windows-zip/dynare-latest-win.zip
-    - f=(macOS/pkg/*) && cp ${f[0]} /srv/www.dynare.org/snapshot/macos/ && ln -sf ${f[0]##*/} /srv/www.dynare.org/snapshot/macos/dynare-latest-macos.pkg
-    - ~/update-snapshot-list.sh
-    - curl -X POST -F token="$WEBSITE_PIPELINE_TRIGGER_TOKEN" -F ref=master https://git.dynare.org/api/v4/projects/40/trigger/pipeline
+    - cp *.tar.xz /srv/www.dynare.org/release_ecb/source/
+    - cp windows/exe/* /srv/www.dynare.org/release_ecb/windows/
+    - cp windows/7z/* /srv/www.dynare.org/release_ecb/windows-7z/
+    - cp windows/zip/* /srv/www.dynare.org/release_ecb/windows-zip/
+    - cp macOS/pkg/* /srv/www.dynare.org/release_ecb/macos/
diff --git a/.gitmodules b/.gitmodules
index ccbe16519d536bbcb7b4cb73567ec95ea4c31cfc..b665d1eebe604f3606d2374cfa939d1296842116 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -18,8 +18,8 @@
 	url = ../../Dynare/particles.git
 [submodule "matlab/modules/dseries"]
 	path = matlab/modules/dseries
-	url = ../../Dynare/dseries.git
-	branch = master
+	url = ../../Enterprise/dseries.git
+	branch = enterprise
 [submodule "matlab/modules/reporting"]
 	path = matlab/modules/reporting
 	url = ../../Dynare/reporting.git
@@ -28,4 +28,4 @@
 	url = https://github.com/fangq/jsonlab.git
 [submodule "preprocessor"]
 	path = preprocessor
-	url = ../../Dynare/preprocessor.git
+	url = ../../Enterprise/preprocessor.git
diff --git a/doc/manual/source/running-dynare.rst b/doc/manual/source/running-dynare.rst
index ca23b3dcb19d1deb12f89add6a819d6df5dfa7b7..b7ca7d7dd7203454ae8753702b964c4428e0c5e5 100644
--- a/doc/manual/source/running-dynare.rst
+++ b/doc/manual/source/running-dynare.rst
@@ -229,7 +229,7 @@ by the ``dynare`` command.
     .. option:: json = parse|check|transform|compute
 
         Causes the preprocessor to output a version of the ``.mod`` file in
-        JSON format to ``<<M_.dname>>/model/json/``. 
+        JSON format to ``<<M_.dname>>/model/json/``.
         When the JSON output is created depends on the value
         passed. These values represent various steps of processing in the
         preprocessor.
@@ -258,7 +258,7 @@ by the ``dynare`` command.
     .. option:: jsonstdout
 
         Instead of writing output requested by ``json`` to files,
-        write to standard out, i.e. to the MATLAB/Octave command window 
+        write to standard out, i.e. to the MATLAB/Octave command window
         (and the log-file).
 
     .. option:: onlyjson
@@ -426,6 +426,84 @@ by the ``dynare`` command.
         understands by default that the model to be solved is
         deterministic.
 
+    .. _exclude_eqs:
+
+    .. option:: exclude_eqs=<<equation_tags_to_exclude>>
+
+       Tells Dynare to exclude all equations specified by the argument. As a
+       ``.mod`` file must have the same number of endogenous variables as
+       equations, when `exclude_eqs` is passed, certain rules are followed for
+       excluding endogenous variables. If the ``endogenous`` tag has been set
+       for the excluded equation, the variable it specifies is
+       excluded. Otherwise, if the left hand side of the excluded equation is
+       an expression that contains only one endogenous variable, that variable
+       is excluded. If neither of these conditions hold, processing stops with
+       an error. If an endogenous variable has been excluded by the
+       `exclude_eqs` option and it exists in an equation that has not been
+       excluded, it is transformed into an exogenous variable.
+
+       To specify which equations to exclude, you must pass the argument
+       ``<<equation_tags_to_exclude>>``. This argument takes either a list of
+       equation tags specifying the equations to be excluded or a filename that
+       contains those tags.
+
+       If ``<<equation_tags_to_exclude>>`` is a list of equation tags, it can
+       take one of the following forms:
+
+       #. Given a single argument, e.g. ``exclude_eqs=eq1``, the equation with
+          the tag ``[name='eq1']`` will be excluded. Note that if there is a
+          file called ``eq1`` in the current directory, Dynare will instead
+          try to open this and read equations to exclude from it (see info on
+          filename argument to ``exclude_eqs`` below). Further note that if the
+          tag value contains a space, you must use the variant specified in 2
+          below, i.e. ``exclude_eqs=[eq 1]``.
+       #. Given two or more arguments, e.g. ``exclude_eqs=[eq1, eq 2]``, the
+          equations with the tags ``[name='eq1']`` and ``[name='eq 2']`` will
+          be excluded.
+       #. If you'd like to exclude equations based on another tag name (as
+          opposed to the default ``name``), you can pass the argument as either
+          e.g. ``exclude_eqs=[tagname=a tag]`` if a single equation with tag
+          ``[tagname='a tag']`` is to be excluded or as
+          e.g. ``exclude_eqs=[tagname=(a tag, 'a tag with a, comma')]`` if more
+          than one equation with tags ``[tagname='a tag']`` and ``[tagname='a
+          tag with a, comma']`` will be excluded (note the parenthesis, which
+          are required when more than one equation is specified). Note that if
+          the value of a tag contains a comma, it must be included inside
+          single quotes.
+
+       If ``<<equation_tags_to_exclude>>`` is a filename, the file can take one
+       of the following forms:
+
+       #. One equation per line of the file, where every line represents the
+          value passed to the ``name`` tag. e.g., a file such as::
+
+             eq1
+             eq 2
+
+          would exclude equations with tags ``[name='eq1']`` and ``[name='eq
+          2']``.
+       #. One equation per line of the file, where every line after the first
+          line represents the value passed to the tag specified by the first
+          line. e.g., a file such as::
+
+             tagname=
+             a tag
+             a tag with a, comma
+
+          would exclude equations with tags ``[tagname='a tag']`` and
+          ``[tagname='a tag with a, comma']``. Here note that the first line
+          must end in an equal sign.
+
+    .. option:: include_eqs=<<equation_tags_to_include>>
+
+       Tells Dynare to run with only those equations specified by the
+       argument; in other words, Dynare will exclude all equations not
+       specified by the argument. The argument ``<<equation_tags_to_include>>``
+       is specified in the same way as the argument to :ref:`exclude_eqs
+       <exclude_eqs>`. The functionality of ``include_eqs`` is to find which
+       equations to exclude then take actions in accord with :ref:`exclude_eqs
+       <exclude_eqs>`.
+
     .. option:: use_dll
        :noindex:
 
diff --git a/doc/manual/source/the-model-file.rst b/doc/manual/source/the-model-file.rst
index 92dc4837d3bab5fe9240ce36abbb442c0243d0f9..bd15b5a403a16dcab0e74c129b1866abc7181490 100644
--- a/doc/manual/source/the-model-file.rst
+++ b/doc/manual/source/the-model-file.rst
@@ -1504,7 +1504,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 
             perfect_foresight_setup(periods=200);
             perfect_foresight_solver;
-            
+
 
         In this example, the problem is finding the optimal path for
         consumption and capital for the periods :math:`t=1` to
@@ -1804,7 +1804,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 
     .. option:: datafile = FILENAME
                 filename = FILENAME (deprecated)
-		
+
         The name of the file containing the data. It must be included in quotes if the filename
         contains a path or an extension. The command accepts the following file formats:
 
@@ -1825,7 +1825,7 @@ in this case ``initval`` is used to specify the terminal conditions.
           observation.
 
     .. option:: first_obs = {INTEGER | DATE}
-	       
+
         The observation number or the date (see
 	:ref:`dates-members`) of the first observation to be used in the file
 
@@ -1838,9 +1838,9 @@ in this case ``initval`` is used to specify the terminal conditions.
 	the first period of simulation doesn’t need to exist in the
 	file as the only dates necessary for initialization are before
 	that date.
-	
+
     .. option:: last_obs = {INTEGER | DATE}
-	       
+
         The observaton number or the date (see
 	:ref:`dates-members`) of the last observation to be used in
 	the file.
@@ -1848,11 +1848,11 @@ in this case ``initval`` is used to specify the terminal conditions.
     .. option:: nobs = INTEGER
 
 	The number of observations to be used in the file (starting
-	with first of ``first_obs`` observation).	 
+	with first of ``first_obs`` observation).
 
     .. option:: series = DSERIES NAME
 
-        The name of a DSERIES containing the data (see :ref:`dseries-members`)		
+        The name of a DSERIES containing the data (see :ref:`dseries-members`)
 
     *Example 1*
 
@@ -1866,7 +1866,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -1887,7 +1887,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	``perfect_foresight_setup(periods=200)``.
 	Note that the values for the auxiliary variable corresponding
 	to ``x(-2)`` are automatically computed by ``initval_file``.
-	
+
     *Example 2*
 
         ::
@@ -1900,7 +1900,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -1915,7 +1915,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	The initial and terminal values are taken from file
 	``mydata.csv`` starting with the 10th observation in the
 	file. There must be at least 212 observations in the file.
-	
+
     *Example 3*
 
         ::
@@ -1928,7 +1928,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -1936,7 +1936,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 
 	    ds = dseries(mydata.csv);
 	    lds = log(ds);
-	    
+
 	    initval_file(series=lds,
 	                 first_obs=2010Q1);
 
@@ -1947,7 +1947,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	``lds``. All observations are loaded starting with the 1st quarter of
 	2010 until the end of the file. There must be data available
 	at least until 2050Q3.
-	
+
     *Example 4*
 
         ::
@@ -1960,7 +1960,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -1977,7 +1977,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	dates. All observations are loaded from the 3rd quarter of
 	2009 until the end of the file. There must be data available
 	in the file at least until 2050Q1.
-	
+
     *Example 5*
 
         ::
@@ -1990,7 +1990,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -2006,7 +2006,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	``mydata.csv``. The first 212 observations are loaded and the
 	first 203 observations will be used by
 	``perfect_foresight_setup(periods=200)``.
-	
+
     *Example 6*
 
         ::
@@ -2019,7 +2019,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -2034,7 +2034,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 
 	The initial and terminal values are taken from file
 	``mydata.csv``. Observations 10 to 212 are loaded.
-	   
+
     *Example 7*
 
         ::
@@ -2047,7 +2047,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -2094,7 +2094,7 @@ in this case ``initval`` is used to specify the terminal conditions.
           observation.
 
     .. option:: first_obs = {INTEGER | DATE}
-	       
+
         The observation number or the date (see :ref:`dates-members`) of
 	the first observation to be used in the file
 
@@ -2107,20 +2107,20 @@ in this case ``initval`` is used to specify the terminal conditions.
 	the first period of simulation doesn’t need to exist in the
 	file as the only dates necessary for initialization are before
 	that date.
-	
+
     .. option:: last_obs = {INTEGER | DATE}
-	       
+
         The observation number or the date (see :ref:`dates-members`) of the
 	last observation to be used in the file.
 
     .. option:: nobs = INTEGER
 
 	The number of observations to be used in the file (starting
-	with first of ``first_obs`` observation).	 
+	with first of ``first_obs`` observation).
 
     .. option:: series = DSERIES NAME
 
-        The name of a DSERIES containing the data (see :ref:`dseries-members`)		
+        The name of a DSERIES containing the data (see :ref:`dseries-members`)
 
     *Example 1*
 
@@ -2134,7 +2134,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -2144,14 +2144,14 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    x = 0;
 	    c = exp(c*x/(1 - d));
 	    end;
-	    
+
 	    histval_file(datafile=mydata.csv);
 
 	    stoch_simul(order=1,periods=100);
-	    
+
 	The initial values for the stochastic simulation are taken
 	from the two first rows of file ``mydata.csv``.
-	   
+
     *Example 2*
 
         ::
@@ -2164,7 +2164,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -2178,7 +2178,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	The initial values for the stochastic simulation are taken
 	from rows 10 and 11 of file ``mydata.csv``.
 
-	
+
     *Example 3*
 
         ::
@@ -2191,7 +2191,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -2204,7 +2204,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 
 	The initial values for the stochastic simulation are taken
 	from observations 2010Q1 and 2010Q2 of file ``mydata.csv``.
-	
+
     *Example 4*
 
         ::
@@ -2217,7 +2217,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -2230,7 +2230,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 
 	The initial values for the stochastic simulation are taken
 	from observations 2009Q3 and 2009Q4 of file ``mydata.csv``.
-	
+
     *Example 5*
 
         ::
@@ -2243,7 +2243,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -2256,7 +2256,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 
 	The initial values for the stochastic simulation are taken
 	from the two first rows of file ``mydata.csv``.
-	
+
     *Example 6*
 
         ::
@@ -2269,7 +2269,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -2283,7 +2283,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 
 	The initial values for the stochastic simulation are taken
 	from rows 10 and 11 of file ``mydata.csv``.
-	   
+
     *Example 7*
 
         ::
@@ -2296,7 +2296,7 @@ in this case ``initval`` is used to specify the terminal conditions.
 	    b = -0,6;
 	    c = 0.5;
 	    d = 0.5;
-	    
+
             model;
             x = a*x(-1) + b*x(-2) + e;
             log(c) = c*x + d*log(c(+1));
@@ -2306,13 +2306,13 @@ in this case ``initval`` is used to specify the terminal conditions.
 	                 first_obs=10);
 
             histval_file(datafile=myotherdata.csv);
-	    
+
 	    perfect_foresight_setup(periods=200);
 	    perfect_foresight_solver;
 
 	Historical initial values for the simulation are taken from
 	the two first rows of file ``myotherdata.csv``.
-	
+
         Terminal values and guess values for the simulation are taken
 	from file ``mydata.csv`` starting with the 12th observation in
 	the file. There must be at least 212 observations in the file.
@@ -2716,6 +2716,27 @@ Finding the steady state with Dynare nonlinear solver
                 <http://pages.cs.wisc.edu/~ferris/path.html>`__ and
                 place it in MATLAB’s search path.
 
+           ``12``
+
+                Specialized version of ``2`` for models where all the
+                equations have one endogenous variable on the left
+                hand side and where each equation determines a
+                different endogenous variable. Only expression allowed
+                on the left hand side is the natural logarithm of an
+                endogenous variable. Univariate blocks are solved by
+                evaluating the expression on the right hand
+                side.
+
+           ``14``
+
+                Specialized version of ``4`` for models where all the
+                equations have one endogenous variable on the left
+                hand side and where each equation determines a
+                different endogenous variable. Only expression allowed
+                on the left hand side is the natural logarithm of an
+                endogenous variable. Univariate blocks are solved by
+                evaluating the expression on the right hand side.
+
        |br| Default value is ``4``.
 
     .. option:: homotopy_mode = INTEGER
@@ -3818,8 +3839,8 @@ Computing the stochastic solution
        ``oo_.conditional_variance_decomposition_ME`` (see
        :mvar:`oo_.conditional_variance_decomposition_ME`).  The
        variance decomposition is only conducted, if theoretical
-       moments are requested, *i.e.* using the ``periods=0``-option. 
-       Only available at ``order<3`` and without ``pruning''. In case of ``order=2``, 
+       moments are requested, *i.e.* using the ``periods=0``-option.
+       Only available at ``order<3`` and without ``pruning''. In case of ``order=2``,
        Dynare provides a second-order accurate
        approximation to the true second moments based on the linear
        terms of the second-order solution (see *Kim, Kim,
@@ -4021,8 +4042,8 @@ Computing the stochastic solution
     |br| After a run of ``stoch_simul``, contains the
     variance-covariance of the endogenous variables. Contains
     theoretical variance if the ``periods`` option is not present and simulated variance
-    otherwise. Only available for ``order<4``. At ``order=2`` it will be be 
-    a second-order accurate approximation. At ``order=3``, theoretical moments 
+    otherwise. Only available for ``order<4``. At ``order=2`` it will be be
+    a second-order accurate approximation. At ``order=3``, theoretical moments
     are only available with ``pruning``. The variables are arranged in declaration order.
 
 .. matvar:: oo_.var_list
@@ -4051,8 +4072,8 @@ Computing the stochastic solution
     autocorrelation. The option ar specifies the number of
     autocorrelation matrices available. Contains theoretical
     autocorrelations if the ``periods`` option is not present and simulated
-    autocorrelations otherwise. Only available for ``order<4``. At ``order=2`` it will be be 
-    a second-order accurate approximation. At ``order=3``, theoretical moments 
+    autocorrelations otherwise. Only available for ``order<4``. At ``order=2`` it will be be
+    a second-order accurate approximation. At ``order=3``, theoretical moments
     are only available with ``pruning``.  The field is only created if
     stationary variables are present.
 
@@ -4091,10 +4112,10 @@ Computing the stochastic solution
             If a second order approximation has been requested,
             contains the vector of the mean correction terms.
 
-            Only available at ``order<4``. In case ``order=2``, the 
-            theoretical second moments are a second order accurate 
+            Only available at ``order<4``. In case ``order=2``, the
+            theoretical second moments are a second order accurate
             approximation of the true second moments. See conditional_variance_decomposition.
-            At ``order=3``, theoretical moments are only available with ``pruning``. 
+            At ``order=3``, theoretical moments are only available with ``pruning``.
 
 .. matvar:: oo_.variance_decomposition
 
@@ -4162,9 +4183,9 @@ Computing the stochastic solution
     |br| After a run of ``stoch_simul`` with the
     ``contemporaneous_correlation option``, contains theoretical
     contemporaneous correlations if the ``periods`` option is not
-    present, and simulated contemporaneous correlations otherwise. 
-    Only available for ``order<4``. At ``order=2`` it will be be 
-    a second-order accurate approximation. At ``order=3``, theoretical moments 
+    present, and simulated contemporaneous correlations otherwise.
+    Only available for ``order<4``. At ``order=2`` it will be be
+    a second-order accurate approximation. At ``order=3``, theoretical moments
     are only available with ``pruning``. The variables
     are arranged in declaration order.
 
@@ -7542,25 +7563,25 @@ Shock Decomposition
     .. option:: prefilter = INTEGER
 
         See :opt:`prefilter <prefilter = INTEGER>`.
-        
+
     .. option:: loglinear
-        
+
         See :opt:`loglinear <loglinear>`.
 
     .. option:: diffuse_kalman_tol = DOUBLE
 
         See :opt:`diffuse_kalman_tol <diffuse_kalman_tol = DOUBLE>`.
-        
+
     .. option:: diffuse_filter
-                
+
         See :opt:`diffuse_filter <diffuse_filter>`.
-        
+
     .. option:: xls_sheet = NAME
 
         See :opt:`xls_sheet <xls_sheet = NAME>`.
 
     .. option:: xls_range = RANGE
-        
+
         See :opt:`xls_range <xls_range = RANGE>`.
 
     .. option:: use_shock_groups [= NAME]
@@ -8850,11 +8871,11 @@ Optimal policy under commitment (Ramsey)
 
     This command only creates the expanded model, it doesn’t perform
     any computations. It needs to be followed by other instructions to
-    actually perform desired computations. Examples are calls to ``steady`` 
-    to compute the steady state of the Ramsey economy, to ``stoch_simul`` 
-    with various approximation orders to conduct stochastic simulations based on 
+    actually perform desired computations. Examples are calls to ``steady``
+    to compute the steady state of the Ramsey economy, to ``stoch_simul``
+    with various approximation orders to conduct stochastic simulations based on
     perturbation solutions, to ``estimation`` in order to estimate models
-    under optimal policy with commitment, and to perfect foresight simulation  
+    under optimal policy with commitment, and to perfect foresight simulation
     routines.
 
     See :ref:`aux-variables`, for an explanation of how Lagrange
@@ -8894,12 +8915,12 @@ Optimal policy under commitment (Ramsey)
     ``steady_state_model`` block or in a ``_steadystate.m`` file). In
     this case, it is necessary to provide a steady state solution
     CONDITIONAL on the value of the instruments in the optimal policy
-    problem and declared with the option ``instruments``. The initial value 
-    of the instrument for steady state finding in this case is set with 
-    ``initval``. Note that computing and displaying steady state values 
-    using the ``steady``-command or calls to ``resid`` must come after 
+    problem and declared with the option ``instruments``. The initial value
+    of the instrument for steady state finding in this case is set with
+    ``initval``. Note that computing and displaying steady state values
+    using the ``steady``-command or calls to ``resid`` must come after
     the ``ramsey_model`` statement and the ``initval``-block.
-    
+
     Note that choosing the instruments is partly a matter of interpretation and
     you can choose instruments that are handy from a mathematical
     point of view but different from the instruments you would refer
@@ -8923,8 +8944,8 @@ Optimal policy under commitment (Ramsey)
 
 .. command:: evaluate_planner_objective ;
 
-    This command computes, displays, and stores the value of the 
-    planner objective function 
+    This command computes, displays, and stores the value of the
+    planner objective function
     under Ramsey policy in ``oo_.planner_objective_value``, given the
     initial values of the endogenous state variables. If not specified
     with ``histval``, they are taken to be at their steady state
@@ -8945,7 +8966,7 @@ Optimal policy under commitment (Ramsey)
              ramsey_policy (OPTIONS...) [VARIABLE_NAME...];
 
     |br| This command is formally equivalent to the calling sequence
-    
+
         ::
 
             ramsey_model;
@@ -9015,7 +9036,7 @@ Optimal policy under commitment (Ramsey)
 
     See :comm:`Ramsey steady state <ramsey_model>`.
 
-Optimal policy under discretion 
+Optimal policy under discretion
 -------------------------------
 
 .. command:: discretionary_policy [VARIABLE_NAME...];
@@ -9717,7 +9738,7 @@ Performing identification analysis
               as in *Ratto and Iskrev (2011)*
 
             Note that for orders 2 and 3, all identification checks are based on the pruned
-            state space system as in *Mutschler (2015)*. That is, theoretical moments and 
+            state space system as in *Mutschler (2015)*. That is, theoretical moments and
             spectrum are computed from the pruned ABCD-system, whereas the minimal system
             criteria is based on the first-order system, but augmented by the theoretical
             (pruned) mean at order 2 or 3.
@@ -11609,8 +11630,8 @@ Macro directives
               @#ifdef MACRO_VARIABLE
               @#ifndef MACRO_VARIABLE
               @#elseif MACRO_EXPRESSION
-              @#else ​
-              @#endif ​
+              @#else
+              @#endif
 
     |br| Conditional inclusion of some part of the ``.mod`` file. The lines
     between ``@#if``, ``@#ifdef``, or ``@#ifndef`` and the next ``@#elseif``,
@@ -11698,7 +11719,7 @@ Macro directives
               @#for MACRO_VARIABLE in MACRO_EXPRESSION when MACRO_EXPRESSION
               @#for MACRO_TUPLE in MACRO_EXPRESSION
               @#for MACRO_TUPLE in MACRO_EXPRESSION when MACRO_EXPRESSION
-              @#endfor ​
+              @#endfor
 
     |br| Loop construction for replicating portions of the ``.mod``
     file. Note that this construct can enclose variable/parameters
@@ -11771,7 +11792,7 @@ Macro directives
     |br| Asks the preprocessor to display some error message on standard
     output and to abort. The argument must evaluate to a string.
 
-.. macrodir:: @#echomacrovars ​
+.. macrodir:: @#echomacrovars
               @#echomacrovars MACRO_VARIABLE_LIST
               @#echomacrovars(save) MACRO_VARIABLE_LIST
 
diff --git a/examples/NK_baseline.mod b/examples/NK_baseline.mod
index 8d76473dad4fb4e4322b8aff3a3915c69761adbc..ad035e1b370a461bfb77a0b2ba56f475c81ae334 100644
--- a/examples/NK_baseline.mod
+++ b/examples/NK_baseline.mod
@@ -1,33 +1,33 @@
 /*
- * This file implements the Baseline New Keynesian DSGE model described in 
- * much detail in Jesús Fernández-Villaverde and Juan F. Rubio-Ramírez (2006): “A Baseline DSGE 
+ * This file implements the Baseline New Keynesian DSGE model described in
+ * much detail in Jesús Fernández-Villaverde and Juan F. Rubio-Ramírez (2006): “A Baseline DSGE
  * Model”, available at http://economics.sas.upenn.edu/~jesusfv/benchmark_DSGE.pdf
  *
- * The parametrization is based on the estimated version of this model in 
- * Jesús Fernández-Villaverde (2010): “The econometrics of DSGE models”, 
+ * The parametrization is based on the estimated version of this model in
+ * Jesús Fernández-Villaverde (2010): “The econometrics of DSGE models”,
  * SERIEs, Vol. 1, pp. 3-49, DOI 10.1007/s13209-009-0014-7
  *
  * This implementation was written by Benjamin Born and Johannes Pfeifer. In
  * case you spot mistakes, email us at jpfeifer@gmx.de
  *
- * This mod-file implements a non-linearized version of the New Keynesian 
- * model based on a recursive formulation of the price and wage setting 
- * equations. Moreover, it makes use of a steady state file to i) set 
+ * This mod-file implements a non-linearized version of the New Keynesian
+ * model based on a recursive formulation of the price and wage setting
+ * equations. Moreover, it makes use of a steady state file to i) set
  * parameters that depend on other parameters that are potentially estimated
  * and ii) solve a nonlinear equation using a numerical solver to find the steady
  * state of labor. It provides an example on how the steady state file can be used
  * to circumvent some of the limitation of Dynare mod-file by accessing an external
- * file that allows calling general MATLAB routines. These capacities will mostly be 
- * interesting for power users. If one just wants to provide analytical steady state 
+ * file that allows calling general MATLAB routines. These capacities will mostly be
+ * interesting for power users. If one just wants to provide analytical steady state
  * values and update parameters, the steady_state_model-block allows an easy and convenient
  * alternative. It even allows calling numerical solvers like fsolve. For an example, see
  * example3.mod
- * 
+ *
  * The model is written in the beginning of period stock notation. To make the model
- * conform with Dynare’s end of period stock notation, we use the 
+ * conform with Dynare’s end of period stock notation, we use the
  * predetermined_variables-command.
  *
- * Please note that the following copyright notice only applies to this Dynare 
+ * Please note that the following copyright notice only applies to this Dynare
  * implementation of the model.
  */
 
@@ -79,7 +79,7 @@ var d       (long_name='preference shock')
     phi     (long_name='labor disutility shock')
     F       (long_name='firm profits')
     ;
-    
+
 varexo epsd (long_name='Innovation preference shock')
     epsphi  (long_name='Innovation labor disutility shock')
     epsmu_I (long_name='Innovation investment-specific technology')
@@ -125,7 +125,7 @@ parameters h            (long_name='consumption habits')
 
 //Note that the parameter naming in FV(2010) differs from FV(2006)
 //Fixed parameters, taken from FV(2010), Table 2, p. 37
-delta=0.025; 
+delta=0.025;
 epsilon=10;
 eta= 10;
 Phi=0;
@@ -162,7 +162,7 @@ LambdaA = 2.8e-3;
 
 
 /*
-The following parameters are set in the steady state file as they depend on other 
+The following parameters are set in the steady state file as they depend on other
 deep parameters (some were estimated in the original study). Setting them in the
 steady state file means they are updated for every parameter draw in the MCMC
 algorithm, while the parameters initialized here are only set once for the initial
@@ -181,7 +181,7 @@ The following model equations are the stationary model equations, taken from
 FV(2006), p. 20, section 3.2.
 */
 
-model; 
+model;
 [name='FOC consumption']
 d*(c-h*c(-1)*mu_z^(-1))^(-1)-h*betta*d(+1)*(c(+1)*mu_z(+1)-h*c)^(-1)=lambda;
 [name='Euler equation']
@@ -221,7 +221,7 @@ yd=c+x+mu_z^(-1)*mu_I^(-1)*(gammma1*(u-1)+gammma2/2*(u-1)^2)*k;
 [name='Aggregate production']
 yd=(mu_A*mu_z^(-1)*(u*k)^alppha*ld^(1-alppha)-Phi)/vp;
 [name='Aggregate labor market']
-l=vw*ld; 
+l=vw*ld;
 [name='LOM Price dispersion term']
 vp=thetap*(PI(-1)^chi/PI)^(-epsilon)*vp(-1)+(1-thetap)*PIstar^(-epsilon);
 [name='LOM Wage dispersion term']
@@ -241,7 +241,7 @@ log(phi)=rhophi*log(phi(-1))+epsphi;
 [name='Investment specific technology']
 log(mu_I)=Lambdamu+epsmu_I;
 [name='Neutral technology']
-log(mu_A)=LambdaA+epsA; 
+log(mu_A)=LambdaA+epsA;
 [name='Defininition composite technology']
 mu_z=mu_A^(1/(1-alppha))*mu_I^(alppha/(1-alppha));
 
diff --git a/matlab/+equation/evaluate.m b/matlab/+equation/evaluate.m
new file mode 100644
index 0000000000000000000000000000000000000000..ca42c84b23e6ded5cd0eeabd2ba9580d69595932
--- /dev/null
+++ b/matlab/+equation/evaluate.m
@@ -0,0 +1,186 @@
+function [ds, json] = evaluate(ds, eqtags, firstperiod, lastperiod, json)
+
+% Copyright (C) 2019 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/>.
+
+global M_
+
+debug = false;
+
+if ischar(eqtags)
+    eqtags = {eqtags};
+end
+
+list_of_expression_tokens = {'+', '-', '*', '/', '^', ...
+        'exp(', 'log(', 'sqrt(', 'abs(', 'sign(', ...
+        'sin(', 'cos(', 'tan(', 'asin(', 'acos(', 'atan(', ...
+        'min(', 'max(', ...
+        'normcdf(', 'normpdf(', 'erf(', ...
+        'diff(', 'adl(', ')'};
+
+if ismember(nargin, [4, 5])
+    if isempty(firstperiod) && isempty(lastperiod)
+        range = ds.dates(1):ds.dates(end);
+    elseif isempty(firstperiod) && ~isempty(lastperiod)
+        range = ds.dates(1):lastperiod;
+    elseif ~isempty(firstperiod) && isempty(lastperiod)
+        range = firstperiod:ds.dates(end);
+    else
+        range = firstperiod:lastperiod;
+    end
+elseif isequal(nargin, 3)
+    if isempty(firstperiod)
+        range = ds.dates(1):ds.dates(end);
+    else
+        range = firstperiod:ds.dates(end);
+    end
+elseif isequal(nargin, 2)
+    range = ds.dates(1):ds.dates(end);
+else
+    error('This routine admits 2, 3, 4, or 5 input arguments.')
+end
+
+for i=1:length(eqtags)
+    % Get equation
+    if isequal(i, 1)
+        if nargin<5
+            [LHS, RHS, json] = get_lhs_and_rhs(eqtags{i}, M_, true);
+        else
+            [LHS, RHS] = get_lhs_and_rhs(eqtags{i}, M_, true, json);
+        end
+    else
+        [LHS, RHS] = get_lhs_and_rhs(eqtags{i}, M_, true, json);
+    end
+    % Parse equation and return list of parameters, endogenous and exogenous variables.
+    [pnames, enames, xnames] = get_variables_and_parameters_in_equation(LHS, RHS, M_);
+    % Load parameter values.
+    if ~isempty(pnames)
+        commands = sprintf('%s = %s;', pnames{1}, num2str(M_.params(strcmp(pnames{1}, M_.param_names)), 16));
+        for j=2:length(pnames)
+            commands = sprintf('%s %s = %s;', commands, pnames{j}, num2str(M_.params(strcmp(pnames{j}, M_.param_names)), 16));
+        end
+        eval(commands)
+    end
+    % Remove repetitions in enames
+    enames = unique(enames);
+    % Test if LHS is an endogenous variable
+    is_lhs_expression = ~ismember(LHS, enames);
+    if is_lhs_expression
+        variable = strsplit(LHS, list_of_expression_tokens);
+        variable(cellfun(@(x) all(isempty(x)), variable)) = [];
+        if length(variable)>1
+            error('It is not possible to have an expression with more than one variable on the LHS (%s).', LHS)
+        else
+            if isequal(LHS, sprintf('log(%s)', variable{1}))
+                transform = {'exp'};
+            elseif isequal(LHS, sprintf('diff(%s)', variable{1}))
+                transform = {'cumsum'};
+            elseif isequal(LHS, sprintf('diff(log(%s))', variable{1}))
+                transform = {'cumsum', 'exp'};
+            elseif isequal(LHS, sprintf('diff(diff(%s))', variable{1}))
+                transform = {'cumsum', 'cumsum'};
+            elseif isequal(LHS, sprintf('diff(diff(log(%s)))', variable{1}))
+                transform = {'cumsum', 'cumsum', 'exp'};
+            else
+                error('Cannot proceed with provided LHS (%s in %s)', LHS, eqtags{i})
+            end
+            lhs = variable{1};
+        end
+    else
+        lhs = LHS;
+        transform = {};
+    end
+    % Throw an error if the equation is dynamic.
+    if exactcontains(RHS, lhs)
+        error('RHS cannot contain LHS variable (%s in %s)', lhs, eqtags{i})
+    end
+    % Substitute endogenous variable x with ds.
+    for j=1:length(enames)
+        if ismember(enames{j}, ds.name)
+            RHS = exactstrrep(RHS, enames{j}, sprintf('ds(range).%s', enames{j}));
+        else
+            RHS = exactstrrep(RHS, sprintf('(%s\\((\\-)*\\d\\)|%s)', enames{j}, enames{j}), '0');
+            if debug
+                warning off backtrace
+                warning('Endogenous variable %s is unknown in dseries objet. Assign zero value.', enames{j})
+                warning on backtrace
+            end
+        end
+    end
+    % Substitute exogenous variable x with ds.x, except if
+    if ~isfield(M_, 'simulation_exo_names')
+        M_.simulation_exo_names = M_.exo_names;
+    end
+    xnames = unique(xnames);
+    for j=1:length(xnames)
+        if ismember(xnames{j}, M_.simulation_exo_names)
+            if ismember(xnames{j}, ds.name)
+                RHS = exactstrrep(RHS, xnames{j}, sprintf('ds(range).%s', xnames{j}));
+            else
+                RHS = exactstrrep(RHS, xnames{j}, '0');
+                if debug
+                    warning off backtrace
+                    warning('Exogenous variable %s is unknown in dseries objet. Assign zero value.', xnames{j})
+                    warning on backtrace
+                end
+            end
+        else
+            RHS = regexprep(RHS, sprintf('(\\ *)(+)(\\ *)%s', xnames{j}), '');
+        end
+    end
+    if isempty(transform)
+        ds{LHS} = eval(RHS);
+    else
+        tmp = eval(RHS);
+        switch length(transform)
+          case 1
+            if isequal(transform{1}, 'cumsum')
+                ds{lhs} = cumsum(tmp)+ds{lhs}(range(1)-1).data;
+            else
+                ds{lhs} = feval(transform{1}, tmp);
+            end
+          case 2
+            if isequal(transform{2}, 'cumsum')
+                % Squared first difference.
+                t2 = zeros(length(range), 1);
+                for t = 1:length(range)
+                    t2(t) = 2*ds{lhs}(range(t)-1).data-ds{lhs}(range(t)-2).data+tmp(range(t)).data;
+                end
+                ds{lhs} = dseries(t2, range(1));
+            else
+                t2 = zeros(length(range), 1);
+                for t = 1:length(range)
+                    t1 = feval(transform{2}, log(ds{lhs}(range(t)-1))+tmp(range(t)).data );
+                    t2(t) = t1.data;
+                end
+                ds{lhs} = dseries(t2, range(1));
+% $$$                 % The commented version below is more efficient but the discrepancy with what is returned by simulating
+% $$$                 % the model is much bigger (see pac/trend-component-28/example4.mod).
+% $$$                 tmp = cumsum(tmp)+log(ds{lhs}(range(1)-1).data);
+% $$$                 ds{lhs} = feval(transform{2}, tmp);
+            end
+          case 3
+                t2 = zeros(length(range), 1);
+                for t = 1:length(range)
+                    t2(t) = feval(transform{3}, 2*log(ds{lhs}(range(t)-1).data)-log(ds{lhs}(range(t)-2).data)+tmp(range(t)).data);
+                end
+                ds{lhs} = dseries(t2, range(1));
+          otherwise
+            error('More than 3 unary ops. in LHS not implemented.')
+        end
+    end
+end
\ No newline at end of file
diff --git a/matlab/+gui/+perfect_foresight/run.m b/matlab/+gui/+perfect_foresight/run.m
index 8bd81ff5938f1a1e4abf0c7cd71846feb04d2ff5..52c7298f2dea4d1538b0be44226c0aa914803589 100644
--- a/matlab/+gui/+perfect_foresight/run.m
+++ b/matlab/+gui/+perfect_foresight/run.m
@@ -42,7 +42,7 @@ if nargout > 1
 end
 
 %% Read JSON
-jm = loadjson(json, 'SimplifyCell', 1);
+jm = loadjson_(json, 'SimplifyCell', 1);
 
 %% INITVAL instructions
 % initialize exogenous shocks to zero and compute initial steady state
diff --git a/matlab/+gui/+stochastic-simulation/read.m b/matlab/+gui/+stochastic-simulation/read.m
index dc72318942483c55fa16438141e4a708bf128a26..65099482c89c4e34d37170ed6a0afae5d463139c 100644
--- a/matlab/+gui/+stochastic-simulation/read.m
+++ b/matlab/+gui/+stochastic-simulation/read.m
@@ -33,7 +33,7 @@ function read(json)
 global M_ options_ oo_
 
 %loading JSON
-jm = loadjson(json, 'SimplifyCell', 1);
+jm = loadjson_(json, 'SimplifyCell', 1);
 data2json=struct();
 
 M_.exo_det_length = 0;
diff --git a/matlab/+pac/+bgp/get.m b/matlab/+pac/+bgp/get.m
new file mode 100644
index 0000000000000000000000000000000000000000..06dc69210acd8379c2d62174b4ead1e1710fc35e
--- /dev/null
+++ b/matlab/+pac/+bgp/get.m
@@ -0,0 +1,22 @@
+function dummy = get(pacmodel, paceq, kind, id)
+
+% Copyright (C) 2019 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/>.
+
+global M_
+
+dummy = M_.pac.(pacmodel).equations.(M_.pac.(pacmodel).tag_map{strcmp(paceq, M_.pac.(pacmodel).tag_map(:,1)),2}).(kind).bgp(id);
diff --git a/matlab/+pac/+bgp/set.m b/matlab/+pac/+bgp/set.m
new file mode 100644
index 0000000000000000000000000000000000000000..bdfb4ad7bdf13ba2cfa8cf7f9e3826a2647252e8
--- /dev/null
+++ b/matlab/+pac/+bgp/set.m
@@ -0,0 +1,60 @@
+function dummy = set(pacmodel, paceq, parameter, isnonzeromean)
+
+% Copyright (C) 2019 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/>.
+
+global M_
+
+eqtag = M_.pac.(pacmodel).tag_map{strcmp(paceq, M_.pac.(pacmodel).tag_map(:,1)),2};
+
+dummy = [];
+idp = find(strcmp(parameter, M_.param_names));
+if ~isempty(idp)
+    if isfield(M_.pac.(pacmodel).equations.(eqtag), 'additive') && length(M_.pac.(pacmodel).equations.(eqtag).additive.vars)>1
+        if ~isfield(M_.pac.(pacmodel).equations.(eqtag).additive, 'bgp')
+            M_.pac.(pacmodel).equations.(eqtag).additive.bgp = false(1, length(M_.pac.(pacmodel).equations.(eqtag).additive.params));
+        end
+        [isparam, ip] = ismember(idp, M_.pac.(pacmodel).equations.(eqtag).additive.params);
+        if isparam
+            M_.pac.(pacmodel).equations.(eqtag).additive.bgp(ip) = isnonzeromean;
+            return
+        end
+    end
+    if isfield(M_.pac.(pacmodel).equations.(eqtag), 'optim_additive')
+        if ~isfield(M_.pac.(pacmodel).equations.(eqtag).optim_additive, 'bgp')
+            M_.pac.(pacmodel).equations.(eqtag).optim_additive.bgp = false(1, length(M_.pac.(pacmodel).equations.(eqtag).optim_additive.params));
+        end
+        [isparam, ip] = ismember(idp, M_.pac.(pacmodel).equations.(eqtag).optim_additive.params);
+        if isparam
+            M_.pac.(pacmodel).equations.(eqtag).optim_additive.bgp(ip) = isnonzeromean;
+            return
+        end
+    end
+    if isfield(M_.pac.(pacmodel).equations.(eqtag), 'non_optimizing_behaviour')
+        if ~isfield(M_.pac.(pacmodel).equations.(eqtag).non_optimizing_behaviour, 'bgp')
+            M_.pac.(pacmodel).equations.(eqtag).non_optimizing_behaviour.bgp = false(1, length(M_.pac.(pacmodel).equations.(eqtag).non_optimizing_behaviour.params));
+        end
+        [isparam, ip] = ismember(idp, M_.pac.(pacmodel).equations.(eqtag).non_optimizing_behaviour.params);
+        if isparam
+            M_.pac.(pacmodel).equations.(eqtag).non_optimizing_behaviour.bgp(ip) = isnonzeromean;
+            return
+        end
+    end
+    warning('Parameter %s is not associated to an exogenous variable in equation %s.', parameter, paceq)
+else
+    error('Parameter %s is unknown.', parameter)
+end
\ No newline at end of file
diff --git a/matlab/+pac/+estimate/init.m b/matlab/+pac/+estimate/init.m
new file mode 100644
index 0000000000000000000000000000000000000000..9b2dbb6721c0738850d0a82473cbc47cfaef0ae5
--- /dev/null
+++ b/matlab/+pac/+estimate/init.m
@@ -0,0 +1,139 @@
+function [pacmodl, lhs, rhs, pnames, enames, xnames, rname, pid, eid, xid, pnames_, ipnames_, params, data, islaggedvariables, eqtag] = ...
+    init(M_, oo_, eqname, params, data, range)
+
+% Copyright (C) 2018-2019 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/>.
+
+% Get the original equation to be estimated
+[LHS, RHS] = get_lhs_and_rhs(eqname, M_, true);
+
+% Check that the equation has a PAC expectation term.
+if ~contains(RHS, 'pac_expectation', 'IgnoreCase', true)
+    error('This is not a PAC equation.')
+end
+
+% Get the name of the PAC model.
+pattern = '(\(model_name\s*=\s*)(?<name>\w+)\)';
+pacmodl = regexp(RHS, pattern, 'names');
+pacmodl = pacmodl.name;
+
+% Get the transformed equation to be estimated.
+[lhs, rhs] = get_lhs_and_rhs(eqname, M_);
+
+% Get the equation tag (in M_.pac.(pacmodl).equations)
+eqtag = M_.pac.(pacmodl).tag_map{strcmp(M_.pac.(pacmodl).tag_map(:,1), eqname),2};
+
+% Get the parameters and variables in the PAC equation.
+[pnames, enames, xnames, pid, eid, xid] = get_variables_and_parameters_in_equation(lhs, rhs, M_);
+
+% Get the list of estimated parameters
+pnames_ = fieldnames(params);
+
+% Check that the estimated parameters are used in the PAC equation.
+ParametersNotInPAC = setdiff(pnames_, pnames);
+if ~isempty(ParametersNotInPAC)
+    skipline()
+    if length(ParametersNotInPAC)>1
+        list = sprintf('  %s\n', ParametersNotInPAC{:});
+        remk = sprintf('  The following parameters:\n\n%s\n  do not appear in the PAC equation.', list);
+    else
+        remk = sprintf('  Parameter %s does not appear in the PAC equation.', ParametersNotInPAC{1});
+    end
+    disp(remk)
+    skipline()
+    error('The estimated parameters must be used in equation %s.', eqname)
+end
+
+% Get indices of estimated parameters.
+ipnames_ = zeros(size(pnames_));
+for i=1:length(ipnames_)
+    ipnames_(i) = find(strcmp(pnames_{i}, M_.param_names));
+end
+
+% If equation is estimated by recursive OLS, ensure that the error
+% correction parameter comes first, followed by the autoregressive
+% parameters (in increasing order w.r.t. the lags).
+stack = dbstack;
+ipnames__ = ipnames_;                              % The user provided order.
+if isequal(stack(2).name, 'iterative_ols')
+    ipnames_ = [M_.pac.(pacmodl).equations.(eqtag).ec.params; M_.pac.(pacmodl).equations.(eqtag).ar.params'];
+    if isfield(M_.pac.(pacmodl).equations.(eqtag), 'optim_additive')
+        ipnames_ = [ipnames_; M_.pac.(pacmodl).equations.(eqtag).optim_additive.params(~isnan(M_.pac.(pacmodl).equations.(eqtag).optim_additive.params))'];
+    end
+    if isfield(M_.pac.(pacmodl).equations.(eqtag), 'additive')
+        ipnames_ = [ipnames_; M_.pac.(pacmodl).equations.(eqtag).additive.params(~isnan(M_.pac.(pacmodl).equations.(eqtag).additive.params))'];
+    end
+    if isfield(M_.pac.(pacmodl).equations.(eqtag), 'share_of_optimizing_agents_index')
+        ipnames_ = [ipnames_; M_.pac.(pacmodl).equations.(eqtag).share_of_optimizing_agents_index];
+    end
+    for i=1:length(ipnames_)
+        if ~ismember(ipnames_(i), ipnames__)
+            % This parameter is not estimated.
+            ipnames_(i) = NaN;
+        end
+    end
+end
+
+% Remove calibrated parameters (if any).
+ipnames_(isnan(ipnames_)) = [];
+
+% Reorder params if needed.
+[~, permutation] = ismember(ipnames__, ipnames_);
+pnames_ = pnames_(permutation);
+params = orderfields(params, permutation);
+
+% Add the auxiliary variables in the dataset.
+data = feval([M_.fname '.dynamic_set_auxiliary_series'], data, M_.params);
+
+% Check that the data for endogenous variables have values.
+if any(isnan(data{enames{:}}(range).data(:)))
+    error('Some variable values are missing in the database.')
+end
+
+% Set the number of exogenous variables.
+xnbr = length(xnames);
+
+% Test if we have a residual and get its name (-> rname).
+if isequal(xnbr, 1)
+    rname = M_.exo_names{strcmp(xnames{1}, M_.exo_names)};
+    if ~all(isnan(data{xnames{1}}.data))
+        error('The residual (%s) must have NaN values in the provided database.', xnames{1})
+    end
+else
+    % We have observed exogenous variables in the PAC equation.
+    tmp = data{xnames{:}}(range).data;
+    idx = find(all(~isnan(tmp))); % Indices for the observed exogenous variables.
+    if isequal(length(idx), length(xnames))
+        error('There is no residual in this equation, all the exogenous variables are observed.')
+    else
+        if length(idx)<length(xnames)-1
+            error('It is not allowed to have more than one residual in a PAC equation')
+        end
+        irname = setdiff(1:length(xnames), idx);
+        rname = xnames{irname};
+    end
+end
+
+
+% Remove residuals from the equation.
+%
+% Note that a plus or minus will remain in the equation, but this seems to
+% be without consequence.
+rhs = regexprep(rhs, rname, '');
+
+% Create a dummy variable
+islaggedvariables = contains(rhs, '(-1)');
\ No newline at end of file
diff --git a/matlab/+pac/+estimate/iterative_ols.m b/matlab/+pac/+estimate/iterative_ols.m
new file mode 100644
index 0000000000000000000000000000000000000000..adacfcf500c598604959a99222eeb632b6faab2b
--- /dev/null
+++ b/matlab/+pac/+estimate/iterative_ols.m
@@ -0,0 +1,444 @@
+function iterative_ols(eqname, params, data, range)
+
+% Estimates the parameters of a PAC equation by Iterative Ordinary Least Squares.
+%
+% INPUTS
+% - eqname       [string]    Name of the pac equation.
+% - params       [struct]    Describes the parameters to be estimated.
+% - data         [dseries]   Database for the estimation
+% - range        [dates]     Range of dates for the estimation.
+%
+% OUTPUTS
+% - none
+%
+% REMARKS
+% [1] The estimation results are printed in the command line window, and the
+%     parameters are updated accordingly in M_.params.
+% [2] The second input is a structure. Each fieldname corresponds to the
+%     name of an estimated parameter, the value of the field is the initial
+%     guess used for the estimation (by NLS).
+% [3] The third input is a dseries object which must at least contain all
+%     the variables appearing in the estimated equation. The residual of the
+%     equation must have NaN values in the object.
+% [4] It is assumed that the residual is additive.
+
+% Copyright (C) 2018-2019 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/>.
+
+global M_ oo_ options_
+
+[pacmodl, ~, rhs, ~, ~, ~, rname, ~, ~, ~, ~, ipnames_, params, data, ~, eqtag] = ...
+    pac.estimate.init(M_, oo_, eqname, params, data, range);
+
+% Set initial condition.
+params0 = cell2mat(struct2cell(params));
+
+% Set flag for models with non optimizing agents.
+is_non_optimizing_agents = isfield(M_.pac.(pacmodl).equations.(eqtag), 'non_optimizing_behaviour');
+
+% Set flag for models with exogenous variables (outside of non optimizing agents part)
+if isfield(M_.pac.(pacmodl).equations.(eqtag), 'additive')
+    is_exogenous_variables = length(M_.pac.(pacmodl).equations.(eqtag).additive.vars)>1;
+else
+    is_exogenous_variables = false;
+end
+
+% Set flag for models with exogenous variables (in the optimizing agents part)
+if isfield(M_.pac.(pacmodl).equations.(eqtag), 'optim_additive')
+    is_optim_exogenous_variables = length(M_.pac.(pacmodl).equations.(eqtag).optim_additive.vars)>0;
+else
+    is_optim_exogenous_variables = false;
+end
+
+if is_non_optimizing_agents
+    non_optimizing_behaviour = M_.pac.(pacmodl).equations.(eqtag).non_optimizing_behaviour;
+    non_optimizing_behaviour_params = NaN(length(non_optimizing_behaviour.params), 1);
+    noparams = isnan(non_optimizing_behaviour.params);
+    if ~all(noparams)
+        % Find estimated non optimizing behaviour parameters (if any).
+        non_optimizing_behaviour_estimated_params = ismember(M_.param_names(non_optimizing_behaviour.params), fieldnames(params));
+        if any(non_optimizing_behaviour_estimated_params)
+            error('The estimation of non optimizing behaviour parameters is not yet allowed.')
+        else
+            non_optimizing_behaviour_params(noparams) = 1.0;
+            non_optimizing_behaviour_params(~noparams) = M_.params(non_optimizing_behaviour.params(~noparams));
+        end
+    else
+        non_optimizing_behaviour_params(noparams) = 1.0;
+    end
+    non_optimizing_behaviour_params = non_optimizing_behaviour_params.*transpose(non_optimizing_behaviour.scaling_factor);
+    % Set flag for the estimation of the share of non optimizing agents.
+    estimate_non_optimizing_agents_share = ismember(M_.param_names(M_.pac.(pacmodl).equations.(eqtag).share_of_optimizing_agents_index), fieldnames(params));
+    if ~estimate_non_optimizing_agents_share
+        share_of_optimizing_agents = M_.params(M_.pac.(pacmodl).equations.(eqtag).share_of_optimizing_agents_index);
+        if share_of_optimizing_agents>1 || share_of_optimizing_agents<0
+            error('The share of optimizing agents shoud be in (0,1).')
+        end
+    end
+    share_of_optimizing_agents_index = M_.pac.(pacmodl).equations.(eqtag).share_of_optimizing_agents_index;
+else
+    share_of_optimizing_agents = 1.0;
+    share_of_optimizing_agents_index = [];
+    estimate_non_optimizing_agents_share = false;
+end
+
+if is_exogenous_variables
+    additive = M_.pac.(pacmodl).equations.(eqtag).additive;
+    residual_id = find(strcmp(rname, M_.exo_names));
+    residual_jd = find(additive.vars==residual_id & ~additive.isendo);
+    additive.params(residual_jd) = [];
+    additive.vars(residual_jd) = [];
+    additive.isendo(residual_jd) = [];
+    additive.lags(residual_jd) = [];
+    additive.scaling_factor(residual_jd) = [];
+    additive.estimation  = ismember(additive.params, ipnames_);
+else
+    additive = struct('params', [], 'vars', [], 'isendo', [], 'lags', [], 'scaling_factor', [], 'estimation', []);
+end
+
+if is_optim_exogenous_variables
+    optim_additive = M_.pac.(pacmodl).equations.(eqtag).optim_additive;
+    optim_additive.estimation  = ismember(optim_additive.params, ipnames_);
+else
+    optim_additive = struct('params', [], 'vars', [], 'isendo', [], 'lags', [], 'scaling_factor', [], 'estimation', []);
+end
+
+
+% Build PAC expectation matrix expression.
+dataForPACExpectation0 = dseries();
+listofvariables0 = {};
+if ~isempty(M_.pac.(pacmodl).equations.(eqtag).h0_param_indices)
+    for i=1:length(M_.pac.(pacmodl).equations.(eqtag).h0_param_indices)
+        match = regexp(rhs, sprintf('(?<var>((\\w*)|\\w*\\(-1\\)))\\*%s', M_.param_names{M_.pac.(pacmodl).equations.(eqtag).h0_param_indices(i)}), 'names');
+        if isempty(match)
+            match = regexp(rhs, sprintf('%s\\*(?<var>((\\w*\\(-1\\))|(\\w*)))', M_.param_names{M_.pac.(pacmodl).equations.(eqtag).h0_param_indices(i)}), 'names');
+        end
+        if isempty(strfind(match.var, '(-1)'))
+            listofvariables0{i} = match.var;
+            dataForPACExpectation0 = [dataForPACExpectation0, data{listofvariables0{i}}];
+        else
+            listofvariables0{i} = match.var(1:end-4);
+            dataForPACExpectation0 = [dataForPACExpectation0, data{match.var(1:end-4)}.lag(1)];
+        end
+    end
+    dataPAC0 = dataForPACExpectation0{listofvariables0{:}}(range).data;
+else
+    dataPAC0 = [];
+end
+
+dataForPACExpectation1 = dseries();
+listofvariables1 = {};
+if ~isempty(M_.pac.(pacmodl).equations.(eqtag).h1_param_indices)
+    for i=1:length(M_.pac.(pacmodl).equations.(eqtag).h1_param_indices)
+        match = regexp(rhs, sprintf('(?<var>((\\w*)|(\\w*\\(-1\\))))\\*%s', M_.param_names{M_.pac.(pacmodl).equations.(eqtag).h1_param_indices(i)}), 'names');
+        if isempty(match)
+            match = regexp(rhs, sprintf('%s\\*(?<var>((\\w*\\(-1\\))|(\\w*)))', M_.param_names{M_.pac.(pacmodl).equations.(eqtag).h1_param_indices(i)}), 'names');
+        end
+        if isempty(strfind(match.var, '(-1)'))
+            listofvariables1{i} = match.var;
+            dataForPACExpectation1 = [dataForPACExpectation1, data{listofvariables1{i}}];
+        else
+            listofvariables1{i} = match.var(1:end-4);
+            dataForPACExpectation1 = [dataForPACExpectation1, data{match.var(1:end-4)}.lag(1)];
+        end
+    end
+    dataPAC1 = dataForPACExpectation1{listofvariables1{:}}(range).data;
+else
+    dataPAC1 = [];
+end
+
+% Build data for non optimizing behaviour
+if is_non_optimizing_agents
+    dataForNonOptimizingBehaviour = dseries();
+    for i=1:length(non_optimizing_behaviour.vars)
+        if non_optimizing_behaviour.isendo(i)
+            variable = M_.endo_names{non_optimizing_behaviour.vars(i)};
+        else
+            variable = M_.exo_names{non_optimizing_behaviour.vars(i)};
+        end
+        if non_optimizing_behaviour.lags(i)
+            dataForNonOptimizingBehaviour = [dataForNonOptimizingBehaviour, data{variable}.lag(non_optimizing_behaviour.lags(i))];
+        else
+            dataForNonOptimizingBehaviour = [dataForNonOptimizingBehaviour, data{variable}];
+        end
+    end
+else
+    dataForNonOptimizingBehaviour = dseries();
+end
+
+% Build data for exogenous variables (out of non optimizing behaviour term).
+if is_exogenous_variables
+    listofvariables2 = {}; j = 0;
+    dataForExogenousVariables = dseries();  % Estimated parameters
+    dataForExogenousVariables_ = 0;         % Calibrated parameters
+    is_any_calibrated_parameter_x = false;
+    is_any_estimated_parameter_x = false;
+    for i=1:length(additive.vars)
+        if additive.isendo(i)
+            variable = M_.endo_names{additive.vars(i)};
+        else
+            variable = M_.exo_names{additive.vars(i)};
+        end
+        if additive.estimation(i)
+            j = j+1;
+            is_any_estimated_parameter_x = true;
+            listofvariables2{j} = variable;
+            dataForExogenousVariables = [dataForExogenousVariables, additive.scaling_factor(i)*data{variable}.lag(additive.lags(i))];
+        else
+            is_any_calibrated_parameter_x = true;
+            tmp = data{variable}.lag(additive.lags(i)).data;
+            if ~isnan(additive.params(i))
+                tmp = M_.params(additive.params(i))*tmp;
+            end
+            tmp = additive.scaling_factor(i)*tmp;
+            dataForExogenousVariables_ = dataForExogenousVariables_+tmp;
+        end
+    end
+    if is_any_calibrated_parameter_x
+        dataForExogenousVariables_ = dseries(dataForExogenousVariables_, data.dates(1), 'exogenous_variables_associated_with_calibrated_parameters');
+    end
+else
+    listofvariables2 = {};
+    dataForExogenousVariables = dseries();
+    dataForExogenousVariables_ = dseries();
+end
+
+% Build data for exogenous variables (in the optimizing behaviour term).
+if is_optim_exogenous_variables
+    listofvariables4 = {}; j = 0;
+    dataForOptimExogenousVariables = dseries();  % Estimated parameters
+    dataForOptimExogenousVariables_ = 0;         % Calibrated parameters
+    is_any_calibrated_parameter_optim_x = false;
+    is_any_estimated_parameter_optim_x = false;
+    for i=1:length(optim_additive.vars)
+        if optim_additive.isendo(i)
+            variable = M_.endo_names{optim_additive.vars(i)};
+        else
+            variable = M_.exo_names{optim_additive.vars(i)};
+        end
+        if optim_additive.estimation(i)
+            j = j+1;
+            is_any_estimated_parameter_optim_x = true;
+            listofvariables4{j} = variable;
+            dataForOptimExogenousVariables = [dataForOptimExogenousVariables, optim_additive.scaling_factor(i)*data{variable}.lag(optim_additive.lags(i))];
+        else
+            is_any_calibrated_parameter_optim_x = true;
+            tmp = data{variable}.lag(optim_additive.lags(i)).data;
+            if ~isnan(optim_additive.params(i))
+                tmp = M_.params(optim_additive.params(i))*tmp;
+            end
+            tmp = optim_additive.scaling_factor(i)*tmp;
+            dataForOptimExogenousVariables_ = dataForOptimExogenousVariables_+tmp;
+        end
+    end
+    if is_any_calibrated_parameter_optim_x
+        dataForOptimExogenousVariables_ = dseries(dataForOptimExogenousVariables_, data.dates(1), 'exogenous_variables_associated_with_calibrated_parameters');
+    end
+else
+    listofvariables4 = {};
+    dataForOptimExogenousVariables = dseries();
+    dataForOptimExogenousVariables_ = dseries();
+end
+
+% Reorder ec.vars locally if necessary. Second variable must be the
+% endogenous variable, while the first must be the associated trend.
+if M_.pac.(pacmodl).equations.(eqtag).ec.isendo(2)
+    ecvars = M_.pac.(pacmodl).equations.(eqtag).ec.vars;
+else
+    ecvars = flip(M_.pac.(pacmodl).equations.(eqtag).ec.vars);
+end
+
+%% Build matrix for EC and AR terms.
+DataForOLS = dseries();
+
+% Error correction term is trend minus the level of the endogenous variable.
+DataForOLS{'ec-term'} = data{M_.endo_names{ecvars(1)}}.lag(1)-data{M_.endo_names{ecvars(2)}}.lag(1);
+listofvariables3 = {'ec-term'};
+xparm = { M_.param_names(M_.pac.(pacmodl).equations.(eqtag).ec.params(1))};
+for i = 1:length(M_.pac.(pacmodl).equations.(eqtag).ar.params)
+    if islagof(M_.pac.(pacmodl).equations.(eqtag).ar.vars(i), M_.pac.(pacmodl).equations.(eqtag).lhs_var)
+        DataForOLS = [DataForOLS, data{M_.endo_names{M_.pac.(pacmodl).equations.(eqtag).ar.vars(i)}}];
+        listofvariables3{i+1} = M_.endo_names{M_.pac.(pacmodl).equations.(eqtag).ar.vars(i)};
+        xparm{i+1} = M_.param_names(M_.pac.(pacmodl).equations.(eqtag).ar.params(i));
+    end
+end
+
+XDATA = DataForOLS{listofvariables3{:}}(range).data;
+
+if is_optim_exogenous_variables && is_any_estimated_parameter_optim_x
+    XDATA = [XDATA, dataForOptimExogenousVariables{listofvariables4{:}}(range).data];
+end
+
+if is_exogenous_variables && is_any_estimated_parameter_x
+    XDATA = [XDATA, dataForExogenousVariables{listofvariables2{:}}(range).data];
+end
+
+% Get index in params0 for share of optimizing agents parameter (if
+% not estimated, params_id_0 is empty).
+if is_non_optimizing_agents
+    params_id_0 = find(ipnames_==share_of_optimizing_agents_index);
+else
+    params_id_0 = [];
+end
+
+% Get indices in params0 for EC and AR parameters
+[~, params_id_1] = setdiff(ipnames_, [share_of_optimizing_agents_index, optim_additive.params, additive.params, ]);
+
+% Get indices in params0 for EC and AR parameters plus parameters related to exogenous variables in the optimal part.
+[~, params_id_5] = setdiff(ipnames_, [share_of_optimizing_agents_index, additive.params]);
+
+% Get indices in params0 for other parameters (optimizing agents share plus parameters related to exogenous variables).
+[~, params_id_2] = setdiff(1:length(ipnames_), params_id_1);
+
+% Get indices in params0 for the parameters associated to the exogenous variables.
+params_id_3 = setdiff(params_id_2, params_id_0);
+[~, params_id_3_o] = ismember(optim_additive.params, ipnames_);
+params_id_3_no = setdiff(params_id_3, params_id_3_o);
+
+% Get indices in params0 for EC/AR parameters and parameters associated to the exogenous variables (if any).
+params_id_4 = [params_id_1; params_id_3];
+
+% Get values for EC-AR parameters plus the parameters associated to the exogenous variables (if any).
+params0_ = params0([params_id_1; params_id_3]);
+
+% Get value of the share of optimizing agents.
+if estimate_non_optimizing_agents_share
+    share_of_optimizing_agents = params0(params_id_0);
+end
+
+% Check that the share is in (0,1)
+if share_of_optimizing_agents>1 || share_of_optimizing_agents<0
+    error('Initial value for the share of optimizing agents shoud be in (0,1).')
+end
+
+% Update the vector of parameters.
+M_.params(ipnames_) = params0;
+
+% Update the reduced form PAC expectation parameters and compute the expectations.
+[PacExpectations, M_] = UpdatePacExpectationsData(dataPAC0, dataPAC1, data, range, pacmodl, eqtag, M_, oo_);
+
+noconvergence = true;
+counter = 0;
+
+while noconvergence
+    counter = counter+1;
+    % Set vector for left handside variable
+    YDATA = data{M_.endo_names{M_.pac.(pacmodl).equations.(eqtag).lhs_var}}(range).data;
+    if is_non_optimizing_agents
+        YDATA = YDATA-share_of_optimizing_agents*PacExpectations;
+        YDATA = YDATA-(1-share_of_optimizing_agents)*(dataForNonOptimizingBehaviour(range).data*non_optimizing_behaviour_params);
+    else
+        YDATA = YDATA-PacExpectations;
+    end
+    if is_exogenous_variables && is_any_calibrated_parameter_x
+        YDATA = YDATA-dataForExogenousVariables_(range).data;
+    end
+    if is_optim_exogenous_variables && is_any_calibrated_parameter_optim_x
+        YDATA = YDATA-share_of_optimizing_agents*dataForOptimExogenousVariables_(range).data;
+    end
+    % Run OLS to estimate PAC parameters (autoregressive parameters and error correction parameter).
+    params1_ = (XDATA\YDATA);
+    params1_(1:length(params_id_5)) = params1_(1:length(params_id_5))/share_of_optimizing_agents;
+    % Compute residuals and sum of squareed residuals.
+    r = YDATA-XDATA(:,1:length(params_id_5))*params1_(1:length(params_id_5))*share_of_optimizing_agents;
+    if is_optim_exogenous_variables && is_any_estimated_parameter_optim_x
+        r = r-XDATA(:,length(params_id_5)+1:end)*params1_(length(params_id_5)+1:end);
+    end
+    ssr = r'*r;
+    % Update convergence dummy variable and display iteration info.
+    noconvergence = max(abs(params0_-params1_))>1e-6;
+    fprintf('Iter. %u,\t crit: %10.5f\t ssr: %10.8f\n', counter, max(abs(params0_-params1_)), ssr)
+    % Updatevector of estimated parameters.
+    params0_ = params1_;
+    % Update the value of the share of non optimizing agents (if estimated)
+    if estimate_non_optimizing_agents_share
+        % First update the parameters and compute the PAC expectation reduced form parameters.
+        M_.params(ipnames_(params_id_4)) = params0_;
+        [PacExpectations, M_] = UpdatePacExpectationsData(dataPAC0, dataPAC1, data, range, pacmodl, eqtag, M_, oo_);
+        % Set vector for left handside variable.
+        YDATA = data{M_.endo_names{M_.pac.(pacmodl).equations.(eqtag).lhs_var}}(range).data;
+        YDATA = YDATA-dataForNonOptimizingBehaviour(range).data*non_optimizing_behaviour_params;
+        if is_exogenous_variables
+            if is_any_calibrated_parameter_x
+                YDATA = YDATA-dataForExogenousVariables_(range).data;
+            end
+            if is_any_estimated_parameter_x
+               YDATA = YDATA-XDATA(:, length(params_id_1):end)*params0_(length(params_id_1):end);
+            end
+        end
+        % Set vector for regressor.
+        ZDATA = XDATA(:,1:length(params_id_5))*params0_(1:length(params_id_5))+PacExpectations-dataForNonOptimizingBehaviour(range).data*non_optimizing_behaviour_params;
+        if is_optim_exogenous_variables && is_any_calibrated_parameter_optim_x
+            ZDATA = ZDATA+dataForOptimExogenousVariables_(range).data;
+        end
+        % Update the (estimated) share of optimizing agents by running OLS
+        share_of_optimizing_agents = (ZDATA\YDATA);
+        % Force the share of optimizing agents to be in [0,1].
+        share_of_optimizing_agents = max(min(share_of_optimizing_agents, options_.pac.estimation.ols.share_of_optimizing_agents.ub), ...
+                                         options_.pac.estimation.ols.share_of_optimizing_agents.lb);
+        % Issue an error if the share is nor strictly positive
+        if share_of_optimizing_agents<eps()
+            error('On iteration %u the share of optimizing agents is found to be zero. Please increase the default lower bound for this parameter.', counter)
+        end
+        M_.params(ipnames_(params_id_0)) = share_of_optimizing_agents;
+    else
+        M_.params(ipnames_) = params0_;
+        [PacExpectations, M_] = UpdatePacExpectationsData(dataPAC0, dataPAC1, data, range, pacmodl, eqtag, M_, oo_);
+    end
+end
+
+% Save results
+oo_.pac.(pacmodl).equations.(eqtag).ssr = ssr;
+oo_.pac.(pacmodl).equations.(eqtag).residual = r;
+oo_.pac.(pacmodl).equations.(eqtag).estimator = params0_;
+oo_.pac.(pacmodl).equations.(eqtag).parnames = fieldnames(params);
+oo_.pac.(pacmodl).equations.(eqtag).covariance = NaN(length(params0_));
+oo_.pac.(pacmodl).equations.(eqtag).student = NaN(size(params0_));
+
+
+function [PacExpectations, Model] = UpdatePacExpectationsData(dataPAC0, dataPAC1, data, range, pacmodl, eqtag, Model, Output)
+    % Update PAC reduced parameters.
+    Model = pac.update.parameters(pacmodl, Model, Output, false);
+    % Compute PAC expectation.
+    if isempty(dataPAC0)
+        PacExpectations = 0;
+    else
+        PacExpectations = dataPAC0*Model.params(Model.pac.(pacmodl).equations.(eqtag).h0_param_indices);
+    end
+    if ~isempty(dataPAC1)
+        PacExpectations = PacExpectations+dataPAC1*Model.params(Model.pac.(pacmodl).equations.(eqtag).h1_param_indices);
+    end
+    % Add correction for growth neutrality if required.
+    correction = 0;
+    if isfield(Model.pac.(pacmodl), 'growth_linear_comb')
+        for iter = 1:numel(Model.pac.(pacmodl).growth_linear_comb)
+            GrowthVariable = Model.pac.(pacmodl).growth_linear_comb(iter).constant;
+            if Model.pac.(pacmodl).growth_linear_comb(iter).param_id > 0
+                GrowthVariable = GrowthVariable*Model.params(Model.pac.(pacmodl).growth_linear_comb(iter).param_id);
+            end
+            if Model.pac.(pacmodl).growth_linear_comb(iter).exo_id > 0
+                GrowthVariable = GrowthVariable*data{Model.exo_names{Model.pac.(pacmodl).growth_linear_comb(iter).exo_id}}.lag(abs(Model.pac.(pacmodl).growth_linear_comb(iter).lag));
+                GrowthVariable = GrowthVariable(range).data;
+            elseif Model.pac.(pacmodl).growth_linear_comb(iter).endo_id > 0
+                GrowthVariable = GrowthVariable*data{Model.endo_names{Model.pac.(pacmodl).growth_linear_comb(iter).endo_id}}.lag(abs(Model.pac.(pacmodl).growth_linear_comb(iter).lag));
+                GrowthVariable = GrowthVariable(range).data;
+            end
+            correction = correction + GrowthVariable;
+        end
+        correction = correction*Model.params(Model.pac.(pacmodl).growth_neutrality_param_index);
+    end
+    PacExpectations = PacExpectations+correction;
diff --git a/matlab/+pac/+estimate/nls.m b/matlab/+pac/+estimate/nls.m
new file mode 100644
index 0000000000000000000000000000000000000000..f85867e94fe345051b4a2f0ad95f49d265e548d7
--- /dev/null
+++ b/matlab/+pac/+estimate/nls.m
@@ -0,0 +1,338 @@
+function nls(eqname, params, data, range, optimizer, varargin)
+
+% Estimates the parameters of a PAC equation by Nonlinear Least Squares.
+%
+% INPUTS
+% - eqname       [string]    Name of the pac equation.
+% - params       [struct]    Describes the parameters to be estimated.
+% - data         [dseries]   Database for the estimation
+% - range        [dates]     Range of dates for the estimation.
+% - optimizer    [string]    Set the optimization algorithm. Possible values
+%                            are 'fmincon', 'fminunc', 'csminwel',
+%                            'fminsearch', 'simplex' and
+%                            'annealing'. Default is 'csminwel'.
+% - varargin                 List of key/value pairs, each key must be a
+%                            string and values can be strings or real numbers.
+%
+% OUTPUTS
+% - none
+%
+% REMARKS
+% [1] The estimation results are printed in the command line window, and the
+%     parameters are updated accordingly in M_.params.
+% [2] The second input is a structure. Each fieldname corresponds to the
+%     name of an estimated parameter, the value of the field is the initial
+%     guess used for the estimation (by NLS).
+% [3] The third input is a dseries object which must at least contain all
+%     the variables appearing in the estimated equation. The residual of the
+%     equation must have NaN values in the object.
+% [4] It is assumed that the residual is additive.
+% [5] If the used optimization routines handles inequalities over the
+%     estimated parameters, we impose the positivity of the error correction parameter.
+%
+% EXAMPLE
+%
+% pac.estimate.nls('zpac', eparams, dbase, dates('2003Q1'):dates('2016Q3'),'fminunc', 'MaxIter', 50);
+%
+% where zpac is the name of the PAC equation, eparams is a structure
+% containing the guess values for the estimated parameters (in each field),
+% dbase is a dseries object containing the data,
+% dates('2003Q1'):dates('2016Q3') is the range of the sample used for
+% estimation, 'fminunc' is the name of the optimization algorithm (this one
+% is available only if the matylab optimization toolbox is installed), the
+% remaining inputs are the options (key/value) passed to the optimizers.
+
+% Copyright (C) 2018-2019 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/>.
+
+global M_ oo_ options_
+
+is_gauss_newton = false;
+is_lsqnonlin = false;
+if nargin>4 && (isequal(optimizer, 'GaussNewton') || isequal(optimizer, 'lsqnonlin'))
+    switch optimizer
+      case 'GaussNewton'
+        is_gauss_newton = true;
+      case 'lsqnonlin'
+        is_lsqnonlin = true;
+    end
+end
+
+[pacmodl, lhs, rhs, pnames, enames, xnames, ~, pid, eid, xid, ~, ipnames_, params, data, islaggedvariables, eqtag] = ...
+    pac.estimate.init(M_, oo_, eqname, params, data, range);
+
+% Check that the error correction term is correct.
+if M_.pac.(pacmodl).equations.(eqtag).ec.istarget(2)
+    error(['\nThe error correction term in PAC equation (%s) is not correct.\nThe ' ...
+           'error correction term should be the difference between a trend\n' ...
+           'and the level of the endogenous variable.'], pacmodl);
+end
+
+% List of objects to be replaced
+objNames = [pnames; enames; xnames];
+objIndex = [pid; eid; xid];
+objTypes = [ones(length(pid), 1); 2*ones(length(eid), 1); 3*ones(length(eid), 1);];
+
+[~,I] = sort(cellfun(@length, objNames), 'descend');
+objNames = objNames(I);
+objIndex = objIndex(I);
+objTypes = objTypes(I);
+
+% Substitute parameters and variables.
+for i=1:length(objNames)
+    switch objTypes(i)
+      case 1
+        rhs = strrep(rhs, objNames{i}, sprintf('DynareModel.params(%u)', objIndex(i)));
+      case {2,3}
+        k = find(strcmp(objNames{i}, data.name));
+        if isempty(k)
+            error('Variable %s is missing in the database.', objNames{i})
+        end
+        j = regexp(rhs, ['\<', objNames{i}, '\>']);
+        if islaggedvariables
+            jlag = regexp(rhs, ['\<(', objNames{i}, '\(-1\))\>']);
+            if ~isempty(jlag)
+                rhs = regexprep(rhs, ['\<(' objNames{i} '\(-1\))\>'], sprintf('data(1:end-1,%u)', k));
+            end
+            if ~isempty(setdiff(j, jlag))
+                rhs = regexprep(rhs, ['\<' objNames{i} '\>'], sprintf('data(2:end,%u)', k));
+            end
+        else
+            rhs = regexprep(rhs, ['\<' objNames{i} '\>'], sprintf('data(:,%u)', k));
+        end
+        if contains(lhs, objNames{i})
+            if islaggedvariables
+                lhs = strrep(lhs, objNames{i}, sprintf('data(2:end,%u)', k));
+            else
+                lhs = strrep(lhs, objNames{i}, sprintf('data(:,%u)', k));
+            end
+        end
+    end
+end
+
+% Create a routine for evaluating the residuals of the nonlinear model
+fun = ['r_' eqname];
+fid = fopen(['+' M_.fname filesep() fun '.m'], 'w');
+fprintf(fid, 'function r = %s(params, data, DynareModel, DynareOutput)\n', fun);
+fprintf(fid, '\n');
+fprintf(fid, '%% Evaluates the residuals for equation %s.\n', eqname);
+fprintf(fid, '%% File created by Dynare (%s).\n', datestr(datetime));
+fprintf(fid, '\n');
+for i=1:length(ipnames_)
+    fprintf(fid, 'DynareModel.params(%u) = params(%u);\n', ipnames_(i), i);
+end
+fprintf(fid, '\n');
+fprintf(fid, 'DynareModel = pac.update.parameters(''%s'', DynareModel, DynareOutput, false);\n', pacmodl);
+fprintf(fid, '\n');
+fprintf(fid, 'r = %s-(%s);\n', lhs, rhs);
+fclose(fid);
+
+% Create a routine for evaluating the sum of squared residuals of the nonlinear model
+fun = ['ssr_' eqname];
+fid = fopen(['+' M_.fname filesep() fun '.m'], 'w');
+fprintf(fid, 'function [s, fake1, fake2, fake3, fake4] = %s(params, data, DynareModel, DynareOutput)\n', fun);
+fprintf(fid, '\n');
+fprintf(fid, '%% Evaluates the sum of square residuals for equation %s.\n', eqname);
+fprintf(fid, '%% File created by Dynare (%s).\n', datestr(datetime));
+fprintf(fid, '\n');
+fprintf(fid, 'fake1 = 0;\n');
+fprintf(fid, 'fake2 = [];\n');
+fprintf(fid, 'fake3 = [];\n');
+fprintf(fid, 'fake4 = [];\n');
+fprintf(fid, '\n');
+for i=1:length(ipnames_)
+    fprintf(fid, 'DynareModel.params(%u) = params(%u);\n', ipnames_(i), i);
+end
+fprintf(fid, '\n');
+fprintf(fid, 'DynareModel = pac.update.parameters(''%s'', DynareModel, DynareOutput, false);\n', pacmodl);
+fprintf(fid, '\n');
+fprintf(fid, 'r = %s-(%s);\n', lhs, rhs);
+fprintf(fid, 's = r''*r;\n');
+fclose(fid);
+
+% Copy (sub)sample data in a matrix.
+DATA = data([range(1)-1, range]).data;
+
+% Create a function handle returning the sum of square residuals for a given vector of parameters.
+ssrfun = @(p) feval([M_.fname '.ssr_' eqname], p, DATA, M_, oo_);
+
+% Create a function handle returning the sum of square residuals for a given vector of parameters.
+resfun = @(p) feval([M_.fname '.r_' eqname], p, DATA, M_, oo_);
+
+% Set initial condition.
+params0 = cell2mat(struct2cell(params));
+
+% Set defaults for optimizers
+bounds = [];
+parameter_names = [];
+
+% Set optimizer routine.
+if nargin<5 || isempty(optimizer)
+    % Use csminwel by default.
+    minalgo = 4;
+else
+    switch optimizer
+      case 'GaussNewton'
+        % Nothing to do here.
+      case 'lsqnonlin'
+        bounds = ones(length(params0),1)*[-Inf,Inf];
+        bounds(strcmp(fieldnames(params), M_.param_names(M_.pac.(pacmodl).equations.(eqtag).ec.params)),1)  = 0.0;
+        bounds(strcmp(fieldnames(params), M_.param_names(M_.pac.(pacmodl).equations.(eqtag).ec.params)),2)  = 1.0;
+      case 'fmincon'
+        if isoctave && ~user_has_octave_forge_package('optim', '1.6')
+            error('Optimization algorithm ''fmincon'' requires the optim package, version 1.6 or higher')
+        elseif ~isoctave && ~user_has_matlab_license('optimization_toolbox')
+            error('Optimization algorithm ''fmincon'' requires the Optimization Toolbox')
+        end
+        minalgo = 1;
+        bounds = ones(length(params0),1)*[-Inf,Inf];
+        bounds(strcmp(fieldnames(params), M_.param_names(M_.pac.(pacmodl).equations.(eqtag).ec.params)),1)  = 0.0;
+        bounds(strcmp(fieldnames(params), M_.param_names(M_.pac.(pacmodl).equations.(eqtag).ec.params)),2)  = 1.0;
+      case 'fminunc'
+        if isoctave && ~user_has_octave_forge_package('optim')
+            error('Optimization algorithm ''fminunc'' requires the optim package')
+        elseif ~isoctave && ~user_has_matlab_license('optimization_toolbox')
+            error('Optimization algorithm ''fminunc'' requires the Optimization Toolbox')
+        end
+        minalgo = 3;
+      case 'csminwel'
+        minalgo = 4;
+      case 'fminsearch'
+        if isoctave && ~user_has_octave_forge_package('optim')
+            error('Optimization algorithm ''fminsearch'' requires the optim package')
+        elseif ~isoctave && ~user_has_matlab_license('optimization_toolbox')
+            error('Optimization algorithm ''fminsearch'' requires the Optimization Toolbox')
+        end
+        minalgo = 7;
+      case 'simplex'
+        minalgo = 8;
+      case 'annealing'
+        minalgo = 2;
+        bounds = ones(length(params0),1)*[-Inf,Inf];
+        bounds(strcmp(fieldnames(params), M_.param_names(M_.pac.(pacmodl).equations.(eqtag).ec.params)),1)  = 0.0;
+        bounds(strcmp(fieldnames(params), M_.param_names(M_.pac.(pacmodl).equations.(eqtag).ec.params)),2)  = 1.0;
+        parameter_names = fieldnames(params);
+      case 'particleswarm'
+        if isoctave
+            error('Optimization ''particleswarm'' is not available under Octave')
+        elseif ~user_has_matlab_license('global_optimization_toolbox')
+            error('Optimization ''particleswarm'' requires the Global Optimization Toolbox')
+        end
+        minalgo = 12;
+        bounds = ones(length(params0),1)*[-Inf,Inf];
+        bounds(strcmp(fieldnames(params), M_.param_names(M_.pac.(pacmodl).equations.(eqtag).ec.params)),1)  = 0.0;
+        bounds(strcmp(fieldnames(params), M_.param_names(M_.pac.(pacmodl).equations.(eqtag).ec.params)),1)  = 1.0;
+        parameter_names = fieldnames(params);
+      otherwise
+        msg = sprintf('%s is not an implemented optimization routine.\n', optimizer);
+        msg = sprintf('%sAvailable algorithms are:\n', msg);
+        msg = sprintf('%s - %s\n', msg, 'fmincon');
+        msg = sprintf('%s - %s\n', msg, 'fminunc');
+        msg = sprintf('%s - %s\n', msg, 'csminwel');
+        msg = sprintf('%s - %s\n', msg, 'fminsearch');
+        msg = sprintf('%s - %s\n', msg, 'simplex');
+        msg = sprintf('%s - %s\n', msg, 'annealing');
+        msg = sprintf('%s - %s\n', msg, 'lsqnonlin');
+        msg = sprintf('%s - %s\n', msg, 'GaussNewton');
+        error(msg)
+    end
+end
+
+% Set options if provided as input arguments to nls routine.
+oldopt = options_.optim_opt;
+if nargin>5
+    if mod(nargin-5, 2)
+        error('Options must come by key/value pairs.')
+    end
+    i = 1;
+    opt = '';
+    while i<nargin-5
+        if i==1
+            opt = sprintf('''%s''', varargin{i});
+        else
+            opt = sprintf('%s,''%s''', opt, varargin{i});
+        end
+        if isnumeric(varargin{i+1})
+            opt = sprintf('%s,%s', opt, num2str(varargin{i+1}));
+        else
+            opt = sprintf('%s,''%s''', opt, varargin{i+1});
+        end
+        i = i+2;
+    end
+    options_.optim_opt = opt;
+else
+    options_.optim_opt = [];
+end
+if nargin<5
+    % If default optimization algorithm is used (csminwel), do not print
+    % iterations.
+    options_.optim_opt = '''verbosity'',0';
+end
+
+if is_gauss_newton
+    [params1, SSR, exitflag] = gauss_newton(resfun, params0);
+elseif is_lsqnonlin
+    if ismember('levenberg-marquardt', varargin)
+        % Levenberg Marquardt does not handle boundary constraints.
+        [params1, SSR, ~, exitflag] = lsqnonlin(resfun, params0, [], [], optimset(varargin{:}));
+    else
+        [params1, SSR, ~, exitflag] = lsqnonlin(resfun, params0, bounds(:,1), bounds(:,2), optimset(varargin{:}));
+    end
+else
+    % Estimate the parameters by minimizing the sum of squared residuals.
+    [params1, SSR, exitflag] = dynare_minimize_objective(ssrfun, params0, ...
+                                                      minalgo, ...
+                                                      options_, ...
+                                                      bounds, ...
+                                                      parameter_names, ...
+                                                      [], ...
+                                                      []);
+end
+
+% Revert local modifications to the options.
+options_.optim_opt = oldopt;
+
+% Compute an estimator of the covariance matrix (see White and
+% Domovitz [Econometrica, 1984], theorem 3.2).
+[r, J] = jacobian(resfun, params1, 1e-6);
+T = length(r);
+A = 2.0*(J'*J)/T;
+J = bsxfun(@times, J, r);
+B = J'*J;
+l = round(T^.25);
+for tau=1:l
+    B = B + (1-tau/(l+1))*(J(tau+1:end,:)'*J(1:end-tau,:)+J(1:end-tau,:)'*J(tau+1:end,:));
+end
+B = (4.0/T)*B;
+C = inv(A)*B*inv(A); % C is the asymptotic covariance of sqrt(T) times the vector of estimated parameters.
+C = C/T;
+
+% Save results
+lhs = eval(strrep(lhs, 'data', 'data(range(1)-1:range(end)).data'));
+oo_.pac.(pacmodl).equations.(eqtag).lhs = dseries(lhs, range(1), sprintf('%s_lhs', eqtag));
+oo_.pac.(pacmodl).equations.(eqtag).fit = dseries(lhs-r, range(1), sprintf('%s_fit', eqtag));
+oo_.pac.(pacmodl).equations.(eqtag).residual = dseries(r, range(1), sprintf('%s_residual', eqtag));
+oo_.pac.(pacmodl).equations.(eqtag).ssr = SSR;
+oo_.pac.(pacmodl).equations.(eqtag).R2 = 1-var(r)/var(lhs);
+oo_.pac.(pacmodl).equations.(eqtag).parnames = fieldnames(params);
+oo_.pac.(pacmodl).equations.(eqtag).estimator = params1;
+oo_.pac.(pacmodl).equations.(eqtag).covariance = C;
+oo_.pac.(pacmodl).equations.(eqtag).student = params1./(sqrt(diag(C)));
+
+% Also save estimated parameters in M_
+M_.params(ipnames_) = params1;
+M_ = pac.update.parameters(pacmodl, M_, oo_, false);
\ No newline at end of file
diff --git a/matlab/+pac/+mce/parameters.m b/matlab/+pac/+mce/parameters.m
new file mode 100644
index 0000000000000000000000000000000000000000..b3e2b01351c2e4d85f82bb3ab044f7633a104ceb
--- /dev/null
+++ b/matlab/+pac/+mce/parameters.m
@@ -0,0 +1,76 @@
+function parameters(pacname)
+
+% Updates the parameters of a PAC Model Consistent Expectations.
+%
+% INPUTS
+% - pacname       [string]    Name of the pac equation.
+%
+% OUTPUTS
+% - none
+%
+% SPECIAL REQUIREMENTS
+%    none
+
+% Copyright (C) 2019 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/>.
+
+global M_
+
+% Check that the first input is a row character array.
+if ~isrow(pacname)==1 || ~ischar(pacname)
+    error('Input argument must be a row character array!')
+end
+
+% Check the name of the PAC model.
+if ~isfield(M_.pac, pacname)
+    error('PAC model %s is not defined in the model block!', pacname)
+end
+
+% Get PAC model description
+pacmodel = M_.pac.(pacname);
+
+% Check that we are dealing with PAC/MCE
+if ~pacmodel.model_consistent_expectations
+    error('This function is to be used only for PAC Model Consistent Expectations.')
+end
+
+% Show the equations where this PAC model is used.
+number_of_pac_eq = size(pacmodel.tag_map, 1);
+if number_of_pac_eq==1
+    fprintf('PAC model %s is used in equation %s.\n', pacname, pacmodel.tag_map{1,1});
+else
+    fprintf('PAC model %s is used in %u equation(s):\n', pacname, number_of_pac_eq);
+    skipline()
+    for i=1:number_of_pac_eq
+        fprintf('    -  %s\n', pacmodel.tag_map{i,1});
+    end
+end
+skipline()
+
+equations = pacmodel.equations;
+
+for e=1:number_of_pac_eq
+    % Get PAC equation tag
+    eqtag = pacmodel.tag_map{e,2};
+    % Get PAC equation
+    pac_equation = equations.(eqtag);
+    % Get Error correction and autoregressive parameters in PAC equation
+    a = NaN(1+pac_equation.max_lag, 1);
+    a(1) = M_.params(pac_equation.ec.params);
+    a(1+(1:pac_equation.max_lag)) = M_.params(pac_equation.ar.params);
+    M_.params(pac_equation.mce.alpha) = a2alpha(a);
+end
\ No newline at end of file
diff --git a/matlab/+pac/+update/equation.m b/matlab/+pac/+update/equation.m
new file mode 100644
index 0000000000000000000000000000000000000000..ac65371b3e620c390c9a46cc0eba6620b0588b46
--- /dev/null
+++ b/matlab/+pac/+update/equation.m
@@ -0,0 +1,34 @@
+function equation(pacname)
+
+% Updates the parameters of a PAC expectation.
+%
+% INPUTS
+% - pacname       [string]    Name of the pac expectation.
+% 
+% OUTPUTS
+% - none
+%
+% SPECIAL REQUIREMENTS
+%    none
+
+% Copyright (C) 2018 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/>.
+
+warning('Function pac.update.equation() is deprecated. Use pac.update.expectation() instead.')
+skipline()
+
+pac.update.expectation(pacname);
\ No newline at end of file
diff --git a/matlab/+pac/+update/expectation.m b/matlab/+pac/+update/expectation.m
new file mode 100644
index 0000000000000000000000000000000000000000..5dc7784dca3270b273c77baf65705ac267a2bbc5
--- /dev/null
+++ b/matlab/+pac/+update/expectation.m
@@ -0,0 +1,33 @@
+function expectation(pacname)
+
+% Updates the parameters of a PAC expectation.
+%
+% INPUTS
+% - pacname       [string]    Name of the pac expectation.
+% 
+% OUTPUTS
+% - none
+%
+% SPECIAL REQUIREMENTS
+%    none
+
+% Copyright (C) 2018 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/>.
+
+global M_ oo_
+
+M_ = pac.update.parameters(pacname, M_, oo_);
\ No newline at end of file
diff --git a/matlab/+pac/+update/parameters.m b/matlab/+pac/+update/parameters.m
new file mode 100644
index 0000000000000000000000000000000000000000..cdd81655b4e7fe791753aef2cc9b05b54e7960c3
--- /dev/null
+++ b/matlab/+pac/+update/parameters.m
@@ -0,0 +1,199 @@
+function DynareModel = parameters(pacname, DynareModel, DynareOutput, verbose)
+
+% Updates the parameters of a PAC equation.
+%
+% INPUTS
+% - pacname       [string]    Name of the pac equation.
+% - DynareModel   [struct]    M_ global structure (model properties)
+% - DynareOutput  [struct]    oo_ global structure (model results)
+%
+% OUTPUTS
+% - none
+%
+% SPECIAL REQUIREMENTS
+%    none
+
+% Copyright (C) 2018-2019 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/>.
+
+if nargin<4
+    verbose = true;
+end
+
+% Check that the first input is a row character array.
+if ~isrow(pacname)==1 || ~ischar(pacname)
+    error('First input argument must be a row character array!')
+end
+
+% Check the name of the PAC model.
+if ~isfield(DynareModel.pac, pacname)
+    error('PAC model %s is not defined in the model block!', pacname)
+end
+
+% Get PAC model description
+pacmodel = DynareModel.pac.(pacname);
+
+if pacmodel.model_consistent_expectations
+    error('This function cannot be used with Model Consistent Expectation. Try pac.mce.parameters instead.')
+end
+
+% Get the name of the associated auxiliary model (VAR or TREND_COMPONENT) model and test its existence.
+if ~isfield(DynareModel.(pacmodel.auxiliary_model_type), pacmodel.auxiliary_model_name)
+    error('Unknown auxiliary model (%s) in PAC model (%s)!', pacmodel.auxiliary_model_name, pacname)
+end
+varmodel = DynareModel.(pacmodel.auxiliary_model_type).(pacmodel.auxiliary_model_name);
+% Check that we have the values of the VAR or TREND_COMPONENT matrices.
+if ~isfield(DynareOutput.(pacmodel.auxiliary_model_type), pacmodel.auxiliary_model_name)
+    error('Auxiliary model %s has to be estimated first!', pacmodel.auxiliary_model_name)
+end
+varcalib = DynareOutput.(pacmodel.auxiliary_model_type).(pacmodel.auxiliary_model_name);
+if ~isfield(varcalib, 'CompanionMatrix') || any(isnan(varcalib.CompanionMatrix(:)))
+    error('Auxiliary model %s has to be estimated first.', pacmodel.auxiliary_model_name)
+end
+
+% Show the equations where this PAC model is used.
+number_of_pac_eq = size(pacmodel.tag_map, 1);
+if verbose
+    fprintf('PAC model %s is used in %u equation(s):\n', pacname, number_of_pac_eq);
+    skipline()
+    for i=1:number_of_pac_eq
+        fprintf('    - %s\n', pacmodel.tag_map{i,1});
+    end
+    skipline()
+end
+
+equations = pacmodel.equations;
+
+for e=1:number_of_pac_eq
+    eqtag = pacmodel.tag_map{e,2};
+    % Build the vector of PAC parameters (ECM parameter + autoregressive parameters).
+    pacvalues = DynareModel.params([equations.(eqtag).ec.params; equations.(eqtag).ar.params(1:equations.(eqtag).max_lag)']);
+    % Get the indices for the stationary/nonstationary variables in the VAR system.
+    id = find(strcmp(DynareModel.endo_names{equations.(eqtag).ec.vars(equations.(eqtag).ec.istarget)}, varmodel.list_of_variables_in_companion_var));
+    if isempty(id)
+        % Find the auxiliary variables if any
+        ad = find(cell2mat(cellfun(@(x) isauxiliary(x, [8 10]), varmodel.list_of_variables_in_companion_var, 'UniformOutput', false)));
+        if isempty(ad)
+            error('Cannot find the trend variable in the Companion VAR/VECM model.')
+        else
+            for i=1:length(ad)
+                auxinfo = DynareModel.aux_vars(get_aux_variable_id(varmodel.list_of_variables_in_companion_var{ad(i)}));
+                if isequal(auxinfo.endo_index, equations.(eqtag).ec.vars(equations.(eqtag).ec.istarget))
+                    id = ad(i);
+                    break
+                end
+                if isequal(auxinfo.type, 8) && isequal(auxinfo.orig_index, equations.(eqtag).ec.vars(equations.(eqtag).ec.istarget))
+                    id = ad(i);
+                    break
+                end
+            end
+        end
+        if isempty(id)
+            error('Cannot find the trend variable in the Companion VAR/VECM model.')
+        end
+    end
+    if isequal(pacmodel.auxiliary_model_type, 'var')
+        if varmodel.nonstationary(id)
+            idns = id;
+            ids = [];
+        else
+            idns = [];
+            ids = id;
+        end
+    else
+        % Trend component model is assumed.
+        ids = [];
+        idns = id;
+    end
+    % Get the value of the discount factor.
+    beta = DynareModel.params(pacmodel.discount_index);
+    % Is growth argument passed to pac_expectation?
+    if isfield(pacmodel, 'growth_str')
+        growth_flag = true;
+    else
+        growth_flag = false;
+    end
+    % Get h0 and h1 vectors (plus the parameter for the growth neutrality correction).
+    if growth_flag
+        [h0, h1, growthneutrality] = hVectors([pacvalues; beta], varcalib.CompanionMatrix, ids, idns, pacmodel.auxiliary_model_type);
+    else
+        [h0, h1] = hVectors([pacvalues; beta], varcalib.CompanionMatrix, ids, idns, pacmodel.auxiliary_model_type);
+    end
+    % Update the parameters related to the stationary components.
+    if ~isempty(h0)
+        DynareModel.params(pacmodel.equations.(eqtag).h0_param_indices) = h0;
+    else
+        if ~isempty(equations.(eqtag).h0_param_indices)
+            DynareModel.params(equations.(eqtag).h0_param_indices) = .0;
+        end
+    end
+    % Update the parameters related to the nonstationary components.
+    if ~isempty(h1)
+        DynareModel.params(equations.(eqtag).h1_param_indices) = h1;
+    else
+        if ~isempty(equations.(eqtag).h1_param_indices)
+            DynareModel.params(equations.(eqtag).h1_param_indices) = .0;
+        end
+    end 
+    % Update the parameter related to the growth neutrality correction.
+    if isfield(equations.(eqtag), 'non_optimizing_behaviour')
+        gamma = DynareModel.params(equations.(eqtag).share_of_optimizing_agents_index);
+    else
+        gamma = 1.0;
+    end
+    if growth_flag
+        % Growth neutrality as returned by hVector is valid iff
+        % there is no exogenous variables in the model and in the
+        % absence of non optimizing agents.
+        gg = -(growthneutrality-1);
+        cc = 1.0-gamma*gg;
+        if isfield(equations.(eqtag), 'optim_additive')
+            tmp = 0;
+            for i=1:length(equations.(eqtag).optim_additive.params)
+                if isnan(equations.(eqtag).optim_additive.params(i)) && equations.(eqtag).optim_additive.bgp(i)
+                    tmp = tmp + equations.(eqtag).optim_additive.scaling_factor(i);
+                elseif ~isnan(equations.(eqtag).optim_additive.params(i)) && equations.(eqtag).optim_additive.bgp(i)
+                    tmp = tmp + DynareModel.params(equations.(eqtag).optim_additive.params(i))*equations.(eqtag).optim_additive.scaling_factor(i);
+                end
+            end
+            cc = cc - gamma*tmp;
+        end
+        if gamma<1
+            tmp = 0;
+            for i=1:length(equations.(eqtag).non_optimizing_behaviour.params)
+                if isnan(equations.(eqtag).non_optimizing_behaviour.params(i)) && equations.(eqtag).non_optimizing_behaviour.bgp(i)
+                    tmp = tmp + equations.(eqtag).non_optimizing_behaviour.scaling_factor(i);
+                elseif ~isnan(equations.(eqtag).non_optimizing_behaviour.params(i)) && equations.(eqtag).non_optimizing_behaviour.bgp(i)
+                    tmp = tmp + DynareModel.params(equations.(eqtag).non_optimizing_behaviour.params(i))*equations.(eqtag).non_optimizing_behaviour.scaling_factor(i);
+                end
+            end
+            cc = cc - (1.0-gamma)*tmp;
+        end
+        if isfield(equations.(eqtag), 'additive')
+            tmp = 0;
+            for i=1:length(equations.(eqtag).additive.params)
+                if isnan(equations.(eqtag).additive.params(i)) && equations.(eqtag).additive.bgp(i)
+                    tmp = tmp + equations.(eqtag).additive.scaling_factor(i);
+                elseif ~isnan(equations.(eqtag).additive.params(i)) && equations.(eqtag).additive.bgp(i)
+                    tmp = tmp + DynareModel.params(equations.(eqtag).additive.params(i))*equations.(eqtag).additive.scaling_factor(i);
+                end
+            end
+            cc = cc - tmp;
+        end
+        DynareModel.params(pacmodel.growth_neutrality_param_index) = cc;
+    end
+end
\ No newline at end of file
diff --git a/matlab/+pac/check.m b/matlab/+pac/check.m
new file mode 100644
index 0000000000000000000000000000000000000000..05f64ee6589ef53993f4e130ad957be98d34fcbb
--- /dev/null
+++ b/matlab/+pac/check.m
@@ -0,0 +1,97 @@
+function errorcode = check(eqname, errorflag)
+
+% Checks that error correction term is well defined in PAC equation.
+%
+% INPUTS
+% - eqname       [string]    Name of the pac equation.
+% OUTPUTS
+% - errorcode    [integer]   Error code, positive if there is an issue with the PAC equation
+%                            0  ->  No error,
+%                            1  ->  eqname has to PAC expectation term,
+%                            2  ->  LHS is not a variable in difference,
+%                            3  ->  Possible calibration issue on the error correction term (should be positive),
+%                            4  ->  Error correction term is missing.
+
+% Copyright (C) 2018 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/>.
+
+global M_
+
+% Set default for second input argument.
+if nargin<2
+    errorflag = true;
+end
+
+% Set default for the returned argument.
+errorcode = 0;
+
+% Get the original equation to be estimated
+[LHS, RHS] = get_lhs_and_rhs(eqname, M_, true);
+
+% Check that the equation has a PAC expectation term.
+if ~contains(RHS, 'pac_expectation', 'IgnoreCase', true)
+    errorcode = 1;
+    if errorflag
+        skipline()
+        error('This is not a PAC equation.')
+    end
+end
+
+% Get the name of the PAC model.
+pattern = '(\(model_name\s*=\s*)(?<name>\w+)\)';
+pacmodl = regexp(RHS, pattern, 'names');
+pacmodl = pacmodl.name;
+
+% Get the index of the lhs variable from M_.pac.
+lhsid = M_.pac.(pacmodl).lhs_var;
+
+% Get info about lhs variable.
+auxinfo = M_.aux_vars(get_aux_variable_id(lhsid));
+
+% Check that the LHS variable is a variable in difference.
+if ~isequal(auxinfo.type, 8)
+    errorcode = 2;
+    if errorflag
+        skipline()
+        error('LHS variable in %s has to be a variable in difference.', eqname)
+    end
+end
+
+% Check that the level of the lhs variable appear on the RHS.
+if ~ismember(auxinfo.orig_index, M_.pac.(pacmodl).ec.vars) || M_.params(M_.pac.(pacmodl).ec.params)<=0
+    if errorflag
+        msg = sprintf('\nPAC equation %s must have an error correction term of the form\n\n', eqname);
+        msg = sprintf('%s  ... +  a*(x(-1)-y(-1)) + ... \n\n', msg);
+        msg = sprintf('%swhere a (%s) is a positive parameter, x (%s) is a the trend/target,\n', ...
+                      msg, M_.param_names{M_.pac.(pacmodl).ec.params}, M_.endo_names{M_.pac.(pacmodl).ec.vars(1)});
+        msg = sprintf('%sand y (%s) is the level of the LHS variable.\n\n', ...
+                      msg, M_.endo_names{auxinfo.orig_index});
+        if M_.params(M_.pac.(pacmodl).ec.params)<=0
+            msg = sprintf('%sPlease change the calibration.\n', msg);
+        else
+            msg = sprintf('%sPlease change the PAC equation.\n', msg);
+        end
+        skipline()
+        error(msg)
+    else
+        if M_.params(M_.pac.(pacmodl).ec.params)<=0
+            errorcode = 3;
+        else
+            errorcode = 4;
+        end
+    end
+end
\ No newline at end of file
diff --git a/matlab/+pac/initialize.m b/matlab/+pac/initialize.m
new file mode 100644
index 0000000000000000000000000000000000000000..052572770c06aef23c242d21813a7d2566ff2c18
--- /dev/null
+++ b/matlab/+pac/initialize.m
@@ -0,0 +1,48 @@
+function initialize(pacmodel)
+
+% Initialization of a PAC model.
+%
+% INPUTS
+% - pacmodel       [string]    Name of the pac model.
+%
+% OUTPUTS
+% None
+
+% Copyright (C) 2018-2019 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/>.
+
+global M_
+
+if isempty(M_.pac.(pacmodel).auxiliary_model_name)
+    M_.pac.(pacmodel).model_consistent_expectations = true;
+else
+    M_.pac.(pacmodel).model_consistent_expectations = false;
+    get_companion_matrix(M_.pac.(pacmodel).auxiliary_model_name, M_.pac.(pacmodel).auxiliary_model_type);
+end
+
+% Append default bgp fields if needed.
+for i=1:rows(M_.pac.(pacmodel).tag_map)
+    if isfield(M_.pac.(pacmodel).equations.(M_.pac.(pacmodel).tag_map{i,2}), 'additive')
+        M_.pac.(pacmodel).equations.(M_.pac.(pacmodel).tag_map{i,2}).additive.bgp = false(1, length(M_.pac.(pacmodel).equations.(M_.pac.(pacmodel).tag_map{i,2}).additive.params));
+    end
+    if isfield(M_.pac.(pacmodel).equations.(M_.pac.(pacmodel).tag_map{i,2}), 'optim_additive')
+        M_.pac.(pacmodel).equations.(M_.pac.(pacmodel).tag_map{i,2}).optim_additive.bgp = false(1, length(M_.pac.(pacmodel).equations.(M_.pac.(pacmodel).tag_map{i,2}).optim_additive.params));
+    end
+    if isfield(M_.pac.(pacmodel).equations.(M_.pac.(pacmodel).tag_map{i,2}), 'non_optimizing_behaviour')
+        M_.pac.(pacmodel).equations.(M_.pac.(pacmodel).tag_map{i,2}).non_optimizing_behaviour.bgp = false(1, length(M_.pac.(pacmodel).equations.(M_.pac.(pacmodel).tag_map{i,2}).non_optimizing_behaviour.params));
+    end
+end
\ No newline at end of file
diff --git a/matlab/+pac/print.m b/matlab/+pac/print.m
new file mode 100644
index 0000000000000000000000000000000000000000..11c3c2a1157075bd636a40d0195eb7b23d331417
--- /dev/null
+++ b/matlab/+pac/print.m
@@ -0,0 +1,44 @@
+function print(pacexpectationmodelname, eqname, withcalibration)
+
+% Prints the exansion of the PAC_EXPECTATION term in files.
+%
+% INPUTS
+% - pacexpectationmodelname       [string]     Name of the expectation model.
+% - eqname                         [string]    Name of the equation.
+% - withcalibration                [logical]   Prints calibration if true.
+%
+% OUTPUTS
+% None
+%
+% REMARKS
+% The routine creates two text files
+%
+% - {pacexpectationmodelname}-parameters.inc     which contains the declaration of the parameters specific to the expectation model kind term.
+% - {pacexpectationmodelname}-expression.inc     which contains the expanded version of the expectation model kind term.
+%
+% These routines are saved under the {modfilename}/model/pacexpectationmodel subfolder, and can be
+% used after in another mod file (ie included with the macro directive @#include).
+
+% Copyright (C) 2018-2019 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/>.
+
+if nargin<3
+    % Print calibration by default.
+    withcalibration = true;
+end
+
+print_expectations(eqname, pacexpectationmodelname, 'pac', withcalibration);
\ No newline at end of file
diff --git a/matlab/+var_expectation/+update/parameters.m b/matlab/+var_expectation/+update/parameters.m
new file mode 100644
index 0000000000000000000000000000000000000000..8052109ec5e7dc06463b55304e3b8538752d7c3d
--- /dev/null
+++ b/matlab/+var_expectation/+update/parameters.m
@@ -0,0 +1,181 @@
+function DynareModel = parameters(varexpectationmodelname, DynareModel, DynareOutput)
+
+% Updates the VAR expectation reduced form parameters.
+%
+% INPUTS
+% - varexpectationmodelname       [string]    Name of the pac equation.
+% - DynareModel                   [struct]    M_ global structure (model properties)
+% - DynareOutput                  [struct]    oo_ global structure (model results)
+%
+% OUTPUTS
+% - DynareModel                   [struct]    M_ global structure (with updated params field)
+%
+% SPECIAL REQUIREMENTS
+%    none
+
+% Copyright (C) 2018 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/>.
+
+% Check that the first input is a row character array.
+if ~isrow(varexpectationmodelname)==1 || ~ischar(varexpectationmodelname)
+    error('First input argument must be a row character array!')
+end
+
+% Check that the model exists.
+if ~isfield(DynareModel.var_expectation, varexpectationmodelname)
+    error('VAR_EXPECTATION_MODEL %s is not defined!', varexpectationmodelname)
+end
+
+% Get the VAR model description
+varexpectationmodel = DynareModel.var_expectation.(varexpectationmodelname);
+
+% Get the name of the associated VAR model and test its existence.
+if ~isfield(DynareModel.(varexpectationmodel.auxiliary_model_type), varexpectationmodel.auxiliary_model_name)
+    error('Unknown VAR (%s) in VAR_EXPECTATION_MODEL (%s)!', varexpectationmodel.auxiliary_model_name, varexpectationmodelname)
+end
+
+auxmodel = DynareModel.(varexpectationmodel.auxiliary_model_type).(varexpectationmodel.auxiliary_model_name);
+
+% Check that we have the values of the VAR matrices.
+if ~isfield(DynareOutput.(varexpectationmodel.auxiliary_model_type), varexpectationmodel.auxiliary_model_name)
+    error('Auxiliary model %s has to be estimated or calibrated first!', varexpectationmodel.auxiliary_model_name)
+end
+
+auxcalib = DynareOutput.(varexpectationmodel.auxiliary_model_type).(varexpectationmodel.auxiliary_model_name);
+
+if ~isfield(auxcalib, 'CompanionMatrix') || any(isnan(auxcalib.CompanionMatrix(:)))
+    message = sprintf('Auxiliary model %s has to be estimated first.', varexpectationmodel.auxiliary_model_name);
+    message = sprintf('%s\nPlease use *get_companion_matrix command first.', message);
+    error(message);
+end
+
+% Set discount factor
+if isfield(varexpectationmodel, 'discount_value')
+    discountfactor = varexpectationmodel.discount_value;
+else
+    if isfield(varexpectationmodel, 'discount_index')
+        discountfactor = DynareModel.params(varexpectationmodel.discount_index);
+    else
+        error('This is most likely a bug. Pleasse conntact the Dynare Team.')
+    end
+end
+
+% A discount factor has to be positive.
+if discountfactor<=0
+    error('The discount factor must be positive.')
+end
+
+% A discount factor cannot be greater than one.
+if discountfactor>1
+    error('The discount cannot be greater than one.')
+end
+
+% Set variables_id in VAR model
+m = length(varexpectationmodel.expr.vars);
+variables_id_in_var = NaN(m,1);
+for i = 1:m
+    j = find(strcmp(auxmodel.list_of_variables_in_companion_var, DynareModel.endo_names{varexpectationmodel.expr.vars(i)}));
+    if isempty(j)
+        error('Cannot find variable %s in the companion VAR', DynareModel.endo_names{varexpectationmodel.expr.vars(i)})
+    else
+        variables_id_in_var(i) = find(strcmp(auxmodel.list_of_variables_in_companion_var, DynareModel.endo_names{varexpectationmodel.expr.vars(i)}));
+    end
+end
+
+% Get the horizon parameter.
+horizon = varexpectationmodel.horizon;
+
+% Check the horizon parameter
+wrong_horizon_parameter = true;
+if length(horizon)==1
+    if isnumeric(horizon)
+        if isfinite(horizon)
+            if isint(horizon)
+                if horizon>0
+                    wrong_horizon_parameter = false;
+                end
+            end
+        end
+    end
+elseif length(horizon)==2
+    if isnumeric(horizon)
+        if isfinite(horizon(1))
+            if isint(horizon(1))
+                if horizon(1)>=0
+                    if isinf(horizon(2)) || (isint(horizon(2)) && horizon(2)>horizon(1)) 
+                        wrong_horizon_parameter = false;
+                    end
+                end
+            end
+        end
+    end
+end
+
+if wrong_horizon_parameter
+    error('horizon must be an integer scalar or an integer vector with two elements.')
+end
+
+% Get the companion matrix
+CompanionMatrix = auxcalib.CompanionMatrix;
+
+% Get the dimension of the problem.
+n = length(CompanionMatrix);
+
+% Set the selection vector
+alpha = zeros(1, n);
+alpha(variables_id_in_var) = varexpectationmodel.expr.constants;
+params_id_in_var = ~isnan(varexpectationmodel.expr.params);
+alpha(variables_id_in_var(params_id_in_var)) = varexpectationmodel.expr.params(params_id_in_var);
+
+if length(horizon)==1
+    % Compute the reduced form parameters of the (discounted) forecast in period t+horizon(1)
+    if varexpectationmodel.horizon==1
+        parameters = discountfactor*(alpha*CompanionMatrix);
+    elseif horizon>1 
+        parameters = alpha*mpower(discountfactor*CompanionMatrix, varexpectationmodel.horizon);
+    end
+else
+    % Compute the reduced form parameters of the discounted sum of forecasts between t+horizon(1) and
+    % t+horizon(2). Not that horzizon(2) need not be finite.
+    if horizon(1)==0 && isinf(horizon(2))
+        parameters = alpha/(eye(n)-discountfactor*CompanionMatrix);
+    elseif horizon(1)>0 && isinf(horizon(2))
+        % Define the discounted companion matrix
+        DiscountedCompanionMatrix = discountfactor*CompanionMatrix;
+        % First compute the parameters implied by the discounted sum from h=0 to h=horizon(1)-1
+        tmp1 = eye(n);
+        for h=1:horizon(1)
+            tmp1 = tmp1 + mpower(DiscountedCompanionMatrix, h); 
+        end
+        tmp1 = alpha*tmp1;
+        % Second compute the parameters implied by the discounted sum from h=0 to h=Inf 
+        tmp2 = alpha/(eye(n)-DiscountedCompanionMatrix);
+        % Finally
+        parameters = tmp2-tmp1;
+    elseif isfinite(horizon(2))
+        % Define the discounted companion matrix
+        DiscountedCompanionMatrix = discountfactor*CompanionMatrix;
+        tmp = zeros(n);
+        for h=horizon(1):horizon(2)
+            tmp = tmp + mpower(DiscountedCompanionMatrix, h);
+        end
+        parameters = alpha*tmp;
+    end
+end
+
+% Update reduced form parameters in M_.params.
+DynareModel.params(varexpectationmodel.param_indices) = parameters;
\ No newline at end of file
diff --git a/matlab/+var_expectation/initialize.m b/matlab/+var_expectation/initialize.m
new file mode 100644
index 0000000000000000000000000000000000000000..06f40eab38aa17ac600845f77af992a20b505399
--- /dev/null
+++ b/matlab/+var_expectation/initialize.m
@@ -0,0 +1,45 @@
+function initialize(varexpectationmodel)
+
+% Initialize a VAR_EXPECTATION_MODEL.
+%
+% INPUTS
+% - varepxpectationmodel       [string]    Name of the VAR expectation model.
+% 
+% OUTPUTS
+% None
+%
+% SPECIAL REQUIREMENTS
+%    none
+
+% Copyright (C) 2018 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/>.
+
+global M_
+
+auxiliary_model_name = M_.var_expectation.(varexpectationmodel).auxiliary_model_name;
+
+if isfield(M_, 'var') && isfield(M_.var, auxiliary_model_name)
+    auxiliary_model_type = 'var';
+elseif isfield(M_, 'trend_component') && isfield(M_.trend_component, auxiliary_model_name)
+    auxiliary_model_type = 'trend_component';
+else
+    error('Unknown type of auxiliary model.')
+end
+
+M_.var_expectation.(varexpectationmodel).auxiliary_model_type = auxiliary_model_type;
+
+get_companion_matrix(auxiliary_model_name, auxiliary_model_type);
\ No newline at end of file
diff --git a/matlab/+var_expectation/print.m b/matlab/+var_expectation/print.m
new file mode 100644
index 0000000000000000000000000000000000000000..05e351f1f03a72d0e7eee826527c2666460e3a96
--- /dev/null
+++ b/matlab/+var_expectation/print.m
@@ -0,0 +1,43 @@
+function print(varexpectationmodelname, withcalibration)
+
+% Prints the exansion of the VAR_EXPECTATION term in files.
+%
+% INPUTS
+% - varepxpectationmodelname       [string]    Name of the expectation model.
+% - withcalibration                [logical]   Prints calibration if true.
+%
+% OUTPUTS
+% None
+%
+% REMARKS
+% The routine creates two text files
+%
+% - {varexpectationmodelname}-parameters.inc     which contains the declaration of the parameters specific to the expectation model kind term.
+% - {varexpectationmodelname}-expression.inc     which contains the expanded version of the expectation model kind term.
+%
+% These routines are saved under the {modfilename}/model/varexpectationmodel subfolder, and can be
+% used after in another mod file (ie included with the macro directive @#include).
+
+% Copyright (C) 2018-2019 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/>.
+
+if nargin<2
+    % Print calibration by default.
+    withcalibration = true;
+end
+
+print_expectations('fake', varexpectationmodelname, 'var', withcalibration);
\ No newline at end of file
diff --git a/matlab/+var_expectation/update.m b/matlab/+var_expectation/update.m
new file mode 100644
index 0000000000000000000000000000000000000000..e7602ee753702e083a31385f354a54e49fbdede0
--- /dev/null
+++ b/matlab/+var_expectation/update.m
@@ -0,0 +1,30 @@
+function update(varexpectationmodelname)
+
+% Updates the parameters of a VAR_EXPECTATION_MODEL.
+%
+% INPUTS
+% - varepxpectationmodelname       [string]    Name of the VAR expectation model.
+% 
+% OUTPUTS
+% None
+
+% Copyright (C) 2018 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/>.
+
+global M_ oo_
+
+M_ = var_expectation.update.parameters(varexpectationmodelname, M_, oo_);
\ No newline at end of file
diff --git a/matlab/aggregate.m b/matlab/aggregate.m
new file mode 100644
index 0000000000000000000000000000000000000000..1f7d4f5af8cd632950811fdebd66ad1a7efca489
--- /dev/null
+++ b/matlab/aggregate.m
@@ -0,0 +1,294 @@
+function aggregate(ofile, dynopt, rootfolder, varargin)
+
+% Agregates cherry-picked models.
+
+% Copyright (C) 2019 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/>.
+
+MAX_NUMBER_OF_ELEMENTS = 10000;
+
+warning off MATLAB:subscripting:noSubscriptsSpecified
+
+if ~isempty(dynopt)
+    % Should be a list of options for the preprocessor in a cell
+    % array.
+    firstline = '// --+ options:';
+    if iscell(dynopt)
+        for i = 1:length(dynopt)
+            firstline = sprintf('%s %s', firstline, dynopt{i});
+        end
+        firstline = sprintf('%s %s', firstline, '+--');
+    else
+        error('Second argument has to be a cell array (list of options for dynare preprocessor).')
+    end
+else
+    firstline = '';
+end
+
+
+% Get parameters.
+for i=1:length(varargin)
+    fid = fopen(sprintf('%s/parameters.inc', varargin{i}));
+    if fid<0
+        % No parameters in the cherrypicked (sub)model, go to the
+        % next cherrypicked model.
+        continue
+    end
+    statement = fgetl(fid);
+    if exist('plist', 'var')
+        plist = union(plist, strsplit(statement, {'parameters', ' ', ';'}));
+    else
+        plist = strsplit(statement, {'parameters', ' ', ';'});
+    end
+    plist(cellfun(@(x) all(isempty(x)), plist)) = [];
+    fclose(fid);
+end
+
+% Get equations
+eqlist = cell(MAX_NUMBER_OF_ELEMENTS, 4);
+tagnum = 1;
+eqnum = 0;
+for i=1:length(varargin)
+    model = importdata(sprintf('%s/model.inc', varargin{i}));
+    eqtag = false;
+    for j=1:length(model)
+        if isequationtag(model{j})
+            if eqtag
+                error('An equation tag must be followed by an equation.')
+            end
+            % Ensure that the equation tag name matches the LHS variable.
+            eqtagname = regexp(model{j}, 'name=''(\w*)''', 'match');
+            [lhs, ~] = getequation(model{j+1});
+            endovar = getendovar(lhs);
+            eqtagname_ = strcat('name=''', endovar{1}, '''');
+            if ~isempty(eqtagname)
+                if ~isequal(eqtagname{1}, eqtagname_)
+                    model{j} = strrep(model{j}, eqtagname{1}, eqtagname_);
+                end
+            else
+                model{j} = eqtagname_;
+            end
+            % Add equation tag with block name.
+            if ~isempty(rootfolder)
+                model{j} = strcat('[blockname=''',  getblockname(varargin{i}, rootfolder), ''',', model{j}(2:end));
+            end
+            eqlist{tagnum,4} = model{j};
+            eqtag = true;
+        else
+            eqnum = eqnum+1;
+            [lhs, rhs] = getequation(model{j});
+            endovar = getendovar(lhs);
+            eqlist{eqnum,1} = endovar{1};
+            eqlist{eqnum,2} = lhs;
+            eqlist{eqnum,3} = rhs;
+            eqtag = false;
+            tagnum = tagnum+1;
+        end
+    end
+end
+eqlist = eqlist(1:eqnum,:);
+[~, idx] = unique(eqlist(:,1), 'stable');
+eqlist = eqlist(idx, :);
+
+% Get endogenous variables.
+elist = cell(MAX_NUMBER_OF_ELEMENTS, 2);
+enum = 0;
+for i=1:length(varargin)
+    fid = fopen(sprintf('%s/endogenous.inc', varargin{i}));
+    cline = fgetl(fid);
+    while ischar(cline)
+        if ~isequal(cline, 'var')
+            enum = enum+1;
+            cline = regexprep(cline, '\t', '');
+            cline = regexprep(cline, ';', '');
+            [v, t] = getvarandtag(cline);
+            elist(enum,1) = {v};
+            elist(enum,2) = {t};
+        end
+        cline = fgetl(fid);
+    end
+    fclose(fid);
+end
+elist = elist(1:enum,:);
+[~, idx] = unique(elist(:,1), 'stable');
+elist = elist(idx,:);
+
+% Get exogenous variables.
+xlist = cell(MAX_NUMBER_OF_ELEMENTS, 2);
+xnum = 0;
+for i=1:length(varargin)
+    fid = fopen(sprintf('%s/exogenous.inc', varargin{i}));
+    if fid<0
+        % No exogenous variables in the cherrypicked (sub)model, go to the
+        % next cherrypicked model.
+        continue
+    end
+    cline = fgetl(fid);
+    while ischar(cline)
+        if ~isequal(cline, 'varexo')
+            xnum = xnum+1;
+            cline = regexprep(cline, '\t', '');
+            cline = regexprep(cline, ';', '');
+            [v, t] = getvarandtag(cline);
+            xlist(xnum,1) = {v};
+            xlist(xnum,2) = {t};
+        end
+        cline = fgetl(fid);
+    end
+    fclose(fid);
+end
+xlist = xlist(1:xnum,:);
+[~, idx] = unique(xlist(:,1), 'stable');
+xlist = xlist(idx,:);
+
+% Get parameter values.
+calibration = '';
+for i=1:length(varargin)
+    fid = fopen(sprintf('%s/parameter-values.inc', varargin{i}));
+    if fid<0
+        % No calibrations in the cherrypicked (sub)model, go to the
+        % next cherrypicked model.
+        continue
+    end
+    cline = fgetl(fid);
+    while ischar(cline)
+        calibration = sprintf('%s\n%s', calibration, cline);
+        cline = fgetl(fid);
+    end
+    fclose(fid);
+end
+
+% Move the endogenous variables which are not LHS of an equation
+% into the set of exogenous variables.
+[~, i1] = intersect(elist(:,1), eqlist(:,1));
+if ~isequal(length(i1),rows(eqlist))
+    error('Something is wrong with the endogenous variables.')
+end
+i2 = setdiff(1:rows(elist), i1);
+xlist = [xlist; elist(i2,:)];
+[~,idx] = unique(xlist(:,1));          % Ensure that the exogenous variable names are unique.
+xlist = [xlist(idx,1) xlist(idx,2)];   % We do not test that the tags are the same.
+elist = elist(i1,:);
+
+% Remove endogenous variables from list of exogenous variables (if any).
+xlist1 = xlist(:,1);
+xlist2 = xlist(:,2);
+[xlist1, id] = setdiff(xlist1, elist(:,1));
+xlist2 = xlist2(id);
+xlist = [xlist1, xlist2];
+
+% Print all cherry-picked models in one mod-file.
+[filepath, filename, fileext] = fileparts(ofile);
+if ~isempty(filepath) && ~exist(filepath, 'dir')
+    mkdir(filepath);
+end
+if isempty(filepath)
+    fid = fopen(sprintf('%s%s', filename, fileext), 'w');
+else
+    fid = fopen(sprintf('%s%s%s%s', filepath, filesep(), filename, fileext), 'w');
+end
+if ~isempty(firstline)
+    fprintf(fid, '%s\n\n', firstline);
+end
+fprintf(fid, 'var\n');
+for i=1:rows(elist)
+    if size(elist,2)==1 || isempty(elist{i,2})
+        fprintf(fid, '\t%s\n', elist{i,1});
+    else
+        fprintf(fid, '\t%s %s\n', elist{i,1}, elist{i,2});
+    end
+end
+if ~isempty(plist)
+    fprintf(fid, ';\n\n');
+    fprintf(fid, 'parameters\n');
+    for i=1:length(plist)
+        fprintf(fid, '\t%s\n', plist{i});
+    end
+    fprintf(fid, ';\n\n');
+    fprintf(fid, calibration);
+end
+if ~isempty(xlist)
+    fprintf(fid, '\n\n');
+    fprintf(fid, 'varexo\n');
+    for i=1:rows(xlist)
+        if size(xlist,2)==1 || isempty(xlist{i,2})
+            fprintf(fid, '\t%s\n', xlist{i,1});
+        else
+            fprintf(fid, '\t%s %s\n', xlist{i,1}, xlist{i,2});
+        end
+    end
+end
+fprintf(fid, ';\n\n');
+fprintf(fid, 'model;\n\n');
+for i=1:rows(eqlist)
+    if isempty(eqlist{i,4})
+        fprintf(fid, '\t%s = %s;\n\n', eqlist{i,2}, eqlist{i,3});
+    else
+        fprintf(fid, '\t%s\n', eqlist{i,4});
+        fprintf(fid, '\t%s = %s;\n\n', eqlist{i,2}, eqlist{i,3});
+    end
+end
+fprintf(fid, 'end;');
+fclose(fid);
+
+warning on MATLAB:subscripting:noSubscriptsSpecified
+
+
+function b = isequationtag(str)
+    b = true;
+    if isempty(regexp(str, '\[.*\]','once'))
+        b = false;
+    end
+
+function [lhs, rhs] = getequation(str)
+    terms = strsplit(str, {'=',';'});
+    terms(cellfun(@(x) all(isempty(x)), terms)) = [];
+    terms(1) = {strrep(terms{1}, ' ', '')};
+    lhs = regexp(terms{1}, '^(diff\([\-]*(log|diff)\([\-\+\*\/\w]*\)\)|(log|diff)\([\(\-\+\*\/\)\w]*\)|\w*)', 'match');
+    if ~isempty(lhs)
+        lhs = lhs{1};
+        if isequal(lhs, 'log')
+           error('Malformed equation: log of log or diff are not allowed.')
+        end
+        rhs = terms{2};
+    else
+        error('Malformed equation.')
+    end
+
+function v = getendovar(lhs)
+    v = strsplit(lhs, {'diff','log','(',')', '+', '-', '*', '/'});
+    v(cellfun(@(x) all(isempty(x)), v)) = [];
+    if length(v)>1
+        error('Malformed equation: no more than one endogenous variable can be used on the LHS.')
+    end
+
+function [v, t] = getvarandtag(str)
+    tmp = regexp(str, '(?<name>\w+)\s*(?<tag>\(.*\))', 'names');
+    if isempty(tmp)
+        tmp = regexp(str, '(?<name>\w+)\s*', 'names');
+        v = tmp.name;
+        t = '';
+    else
+        v = tmp.name;
+        t = tmp.tag;
+    end
+
+function blkname = getblockname(str, ROOT_FOLDER)
+    str = strrep(str, '/', filesep());
+    str = strrep(str, [ROOT_FOLDER filesep() 'blocks' filesep()], '');
+    idx = strfind(str, filesep());
+    blkname = str(1:idx(1)-1);
\ No newline at end of file
diff --git a/matlab/backward/backward_model_irf.m b/matlab/backward/backward_model_irf.m
index 130079003f96b8e1158d53c8bde95850cf13a7b8..a90ffeb33d1455ba5529f79a2e29a4b696b747f3 100644
--- a/matlab/backward/backward_model_irf.m
+++ b/matlab/backward/backward_model_irf.m
@@ -19,7 +19,7 @@ function [deviations, baseline, irfs] = backward_model_irf(initialcondition, inn
 %   argument.
 % - If second argument is not empty, periods must not be greater than innovationbaseline.nobs.
 
-% Copyright (C) 2017-2018 Dynare Team
+% Copyright (C) 2017-2020 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -51,7 +51,7 @@ else
 end
 
 % Set default value for the last input argument (no transformation).
-if nargin<6
+if nargin<6 || isempty(varargin{2})
     notransform = true;
 else
     notransform = false;
@@ -97,6 +97,14 @@ else
     end
 end
 
+% Check fourth argument. If empty return the paths for all the endogenous variables.
+if isempty(listofvariables)
+    listofvariables = M_.endo_names(1:M_.orig_endo_nbr);
+end
+if ~iscell(listofvariables)
+    error('Fourth input argument has to be a cell of row char arrays or an empty object.')
+end
+
 % Set default initial conditions for the innovations.
 for i=1:M_.exo_nbr
     if ~ismember(M_.exo_names{i}, initialcondition.name)
@@ -212,6 +220,7 @@ for i=1:length(listofshocks)
         name = listofshocks{i};
     end
     deviations.(name) = alldeviations{listofvariables{:}};
+    deviations.(name) = [deviations.(name) dseries(innovations, initialcondition.last+1, exonames)];
     if nargout>2
         irfs.(name) = allirfs{listofvariables{:}};
         irfs.(name) = [irfs.(name) dseries(innovations, initialcondition.last+1, exonames)];
@@ -220,5 +229,5 @@ end
 
 if nargout>1
     baseline = dseries(transpose(endo_simul__0), initialcondition.init, endonames(1:M_.orig_endo_nbr), DynareModel.endo_names_tex(1:M_.orig_endo_nbr));
-    baseline = [baseline, innovationbaseline];
+    baseline = merge(baseline, innovationbaseline);
 end
\ No newline at end of file
diff --git a/matlab/backward/calibrateresiduals.m b/matlab/backward/calibrateresiduals.m
index 05c31a284478855badb45d5ac29e83e5ef9a72fe..912ea17ce80dde55cee2c6afee21d32329c483ab 100644
--- a/matlab/backward/calibrateresiduals.m
+++ b/matlab/backward/calibrateresiduals.m
@@ -18,7 +18,7 @@ function [residuals, info] = calibrateresiduals(dbase, info, DynareModel)
 % The first two input arguments are the output of checkdatabaseforinversion
 % routine.
 
-% Copyright (C) 2017 Dynare Team
+% Copyright © 2017-2020 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -35,12 +35,17 @@ function [residuals, info] = calibrateresiduals(dbase, info, DynareModel)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
 
+displayresidualsequationmapping = false;
+
 % Get function handle for the dynamic model
 model_dynamic = str2func([DynareModel.fname,'.dynamic']);
 
 % Get data for all the endogenous variables.
 ydata = dbase{info.endonames{:}}.data;
 
+% Define function to retrieve an equation name
+eqname = @(z) DynareModel.equations_tags{cellfun(@(x) x==z, DynareModel.equations_tags(:,1)) & cellfun(@(x) isequal(x, 'name'), DynareModel.equations_tags(:,2)),3};
+
 % Get data for all the exogenous variables. Missing exogenous variables, to be solved for, have NaN values.
 exogenousvariablesindbase = intersect(info.exonames, dbase.name);
 residuals = dseries(NaN(dbase.nobs, length(info.residuals)), dbase.init, info.residuals);
@@ -77,9 +82,14 @@ if ~isempty(find(abs(r(ido))>1e-6))
         c2 = strvcat(c2, sprintf('%s', num2str(r(idx(i)))));
     end
     c2 = strvcat(c2(1, :), repmat('-', 1, size(c2, 2)), c2(3:end,:));
+    c5 = 'Equation name';
+    c5 = strvcat(c5, '-------------');
+    for i = 1:length(idx)
+        c5 = strvcat(c5, sprintf('  %s', eqname(idx(i))));
+    end
     c3 = repmat(' | ', size(c2, 1), 1);
     c4 = repmat('   ', size(c2, 1), 1);
-    cc = [c4, c1, c3, c2];
+    cc = [c4, c1, c3, c2, c3, c5];
     skipline()
     disp(cc)
     skipline()
@@ -97,22 +107,25 @@ for i = 1:residuals.vobs
     r = model_dynamic(y, tmpxdata, DynareModel.params, zeros(n, 1), 2);
     info.equations(i) = { idr(find(~isnan(r(idr))))};
 end
-c1 = 'Residual';
-for i=1:length(info.residuals)
-    c1 = strvcat(c1, sprintf('%s', info.residuals{i}));
-end
-c1 = strvcat(c1(1,:), repmat('-', 1, size(c1, 2)), c1(2:end,:));
-c2 = 'Equation';
-for i=1:length(info.residuals)
-    c2 = strvcat(c2, sprintf('  %s', num2str(info.equations{i})));
+
+if displayresidualsequationmapping
+    c1 = 'Residual';
+    for i=1:length(info.residuals)
+        c1 = strvcat(c1, sprintf('%s', info.residuals{i}));
+    end
+    c1 = strvcat(c1(1,:), repmat('-', 1, size(c1, 2)), c1(2:end,:));
+    c2 = 'Equation';
+    for i=1:length(info.residuals)
+        c2 = strvcat(c2, sprintf('  %s', num2str(info.equations{i})));
+    end
+    c2 = strvcat(c2(1,:), repmat('-', 1, size(c2, 2)), c2(2:end,:));
+    c3 = repmat(' | ', size(c2, 1), 1);
+    c4 = repmat('   ', size(c2, 1), 1);
+    cc = [c4, c1, c3, c2];
+    skipline()
+    disp(cc)
+    skipline()
 end
-c2 = strvcat(c2(1,:), repmat('-', 1, size(c2, 2)), c2(2:end,:));
-c3 = repmat(' | ', size(c2, 1), 1);
-c4 = repmat('   ', size(c2, 1), 1);
-cc = [c4, c1, c3, c2];
-skipline()
-disp(cc)
-skipline()
 
 % Compute residuals
 xdata(:,cell2mat(info.residualindex)) = 0;
diff --git a/matlab/backward/shock_decomposition_backward.m b/matlab/backward/shock_decomposition_backward.m
new file mode 100644
index 0000000000000000000000000000000000000000..23fc10ce552f6f855e5d3d23902b59a085f563f2
--- /dev/null
+++ b/matlab/backward/shock_decomposition_backward.m
@@ -0,0 +1,113 @@
+function decomposition = shock_decomposition_backward(simulations, initialconditions, shocklist, endograph, use_shock_groups)
+
+% Computes and possibly plots the shock decomposition of a backward (possibly nonlinear)
+% model simulation.
+%
+% Inputs:
+% - simulations          dseries object as returned by simul_backward_model
+% - initialconditions    dseries object as passed to simul_backward_model
+% - shocklist            a cell array listing the (names of the) shocks whose contribution should be
+%                        computed. The order matters: the contribution of a shock appearing at index
+%                        i is computed as the difference between the simulation where all shocks ≥i+1
+%                        are zero and the simulation where all shocks ≥i are zero. It is also
+%                        possible to put in this list shock groups, as defined in a shock_groups
+%                        block
+% - endograph            an optional cell array listing the (names of the) endogenous variables for
+%                        which a shock decomposition graph should be created
+% - use_shock_groups     an optional string giving the name of the shock_groups block to be used to
+%                        resolve shock groups listed in shocklist. If not given, 'default' is used.
+%
+% Output:
+% - decomposition        a 3D array of size endo_nbr×nshocks×nperiods where nshocks=length(shocklist)
+%                        and nperiods is the number of simulation periods (i.e. excluding the initial
+%                        conditions)
+
+% Copyright © 2020 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/>.
+
+global M_ options_
+
+narginchk(3, 5);
+if nargin < 4
+    endograph = {};
+end
+if nargin < 5
+    use_shock_groups = 'default';
+end
+
+% Extract matrix of innovations from the whole simulation paths
+simdates = simulations.dates(initialconditions.nobs+1:end);
+innovations = simulations{M_.exo_names{:}}(simdates);
+
+% Number of simulation periods
+nperiods = simulations.nobs - initialconditions.nobs;
+
+decomposition = NaN(M_.endo_nbr, length(shocklist), nperiods);
+
+% Add auxiliary variables to simulation paths
+if exist(sprintf('+%s/dynamic_set_auxiliary_series', M_.fname), 'file')
+    simulations = feval(sprintf('%s.dynamic_set_auxiliary_series', M_.fname), simulations, M_.params);
+end
+
+for i = length(shocklist):-1:1
+    % Zero the innovation(s) corresponding to this shock or shock group
+    if ismember(shocklist{i}, M_.exo_names)
+        innovations{shocklist{i}}(simdates) = zeros(nperiods, 1);
+    else % This is a shock group
+        if ~ismember(use_shock_groups, fieldnames(M_.shock_groups))
+            error(['Unknown shock_groups block: ' use_shock_groups])
+        end
+        groups = fieldnames(M_.shock_groups.(use_shock_groups));
+        shocks_in_group = [];
+        for j = 1:length(groups)
+            if strcmp(shocklist{i}, M_.shock_groups.(use_shock_groups).(groups{j}).label)
+                shocks_in_group = M_.shock_groups.(use_shock_groups).(groups{j}).shocks;
+                break
+            end
+        end
+        if isempty(shocks_in_group)
+            error(['Unknown shock group: ' shocklist{i}])
+        end
+        for j = 1:length(shocks_in_group)
+            innovations{shocks_in_group{j}}(simdates) = zeros(nperiods, 1);
+        end
+    end
+
+    % Compute simulation with the current shock or shock group removed
+    simulations_new = simul_backward_model(initialconditions, nperiods, innovations);
+    if exist(sprintf('+%s/dynamic_set_auxiliary_series', M_.fname), 'file')
+        simulations_new = feval(sprintf('%s.dynamic_set_auxiliary_series', M_.fname), simulations_new, M_.params);
+    end
+
+    % Compute the contribution of the current shock or shock group
+    contribution = simulations{M_.endo_names{:}}.data(initialconditions.nobs+1:end, :) ...
+                   - simulations_new{M_.endo_names{:}}.data(initialconditions.nobs+1:end, :);
+    decomposition(:, i, :) = contribution';
+
+    simulations = simulations_new;
+end
+
+% Plot the decomposition
+
+for i = 1:length(endograph)
+    h = dyn_figure(options_.plot_shock_decomp.nodisplay, 'Name', [ 'Shock decomposition for ' endograph{i}]);
+    endoidx = find(strcmp(endograph{i}, M_.endo_names));
+    bar(double(simdates), squeeze(decomposition(endoidx, :, :))', 'stacked')
+    legend(shocklist)
+end
+
+end
diff --git a/matlab/backward/simul_backward_nonlinear_model_.m b/matlab/backward/simul_backward_nonlinear_model_.m
index 9839442c37d314bcfc38050acf9e325e30555448..b1d05fc28001b81972b11e9e694350caa8dee9c6 100644
--- a/matlab/backward/simul_backward_nonlinear_model_.m
+++ b/matlab/backward/simul_backward_nonlinear_model_.m
@@ -21,7 +21,7 @@ function [ysim, xsim] = simul_backward_nonlinear_model_(initialconditions, sampl
 % [3] If the first input argument is empty, the endogenous variables are initialized with 0, or if available with the informations
 %     provided thrtough the histval block.
 
-% Copyright (C) 2017 Dynare Team
+% Copyright © 2017-2020 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -38,6 +38,8 @@ function [ysim, xsim] = simul_backward_nonlinear_model_(initialconditions, sampl
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
 
+debug = false;
+
 model_dynamic_s = str2func('dynamic_backward_model_for_simulation');
 
 if ~isempty(innovations)
@@ -46,12 +48,30 @@ end
 
 % Simulations (call a Newton-like algorithm for each period).
 for it = initialconditions.nobs+(1:samplesize)
-    ylag = DynareOutput.endo_simul(iy1,it-1);                   % Set lagged variables.
-    y = DynareOutput.endo_simul(:,it-1);                        % A good guess for the initial conditions is the previous values for the endogenous variables.
-    [DynareOutput.endo_simul(:,it), info, fvec] = dynare_solve(model_dynamic_s, ...
-                                                      y, DynareOptions, model_dynamic, ylag, DynareOutput.exo_simul, DynareModel.params, DynareOutput.steady_state, it);
-    if info
-        error('Newton failed!')
+    if debug
+        dprintf('Période t = %s.', num2str(it-initialconditions.nobs));
+    end
+    y_ = DynareOutput.endo_simul(:,it-1);
+    ylag = y_(iy1);                    % Set lagged variables.
+    y = y_;                            % A good guess for the initial conditions is the previous values for the endogenous variables.
+    try
+        if ismember(DynareOptions.solve_algo, [12,14])
+            [DynareOutput.endo_simul(:,it), info] = ...
+                dynare_solve(model_dynamic_s, y, DynareOptions, ...
+                             DynareModel.isloggedlhs, DynareModel.isauxdiffloggedrhs, DynareModel.endo_names, DynareModel.lhs, ...
+                             model_dynamic, ylag, DynareOutput.exo_simul, DynareModel.params, DynareOutput.steady_state, it);
+        else
+            [DynareOutput.endo_simul(:,it), info] = ...
+                dynare_solve(model_dynamic_s, y, DynareOptions, ...
+                             model_dynamic, ylag, DynareOutput.exo_simul, DynareModel.params, DynareOutput.steady_state, it);
+        end
+        if info
+            error('Newton failed!')
+        end
+    catch
+        DynareOutput.endo_simul(:, 1:it-1);
+        dprintf('Newton failed on iteration i = %s.', num2str(it-initialconditions.nobs));
+        break
     end
 end
 
diff --git a/matlab/cherrypick.m b/matlab/cherrypick.m
new file mode 100644
index 0000000000000000000000000000000000000000..c12a1987c0ccff50c9a2204879df6c561e6c5137
--- /dev/null
+++ b/matlab/cherrypick.m
@@ -0,0 +1,300 @@
+function json = cherrypick(infile, outfold, eqtags, noresids, json)
+
+% Extract some equations in infile (mod file used for estimation)
+% and write them in outfile (mod file used for simulation).
+%
+% INPUTS
+% - infile        [string]    Name of the mod file where all the equations used for estimation are available.
+% - outfold       [string]    Name of the folder where the generated files are saveda subset of the equations is to be printed.
+% - eqtags        [cell]      Equation tags of the selected equations.
+% - noresids      [logical]   Removes estimation residuals (not to be used in simulation) if true.
+% - json          [char]      Content of a JSON file.
+%
+% OUTPUTS
+% - json          [char]      Content of a JSON file.
+%
+% SPECIAL REQUIREMENTS
+% It is expected that the file infile.mod has already been run, and
+% that the associated JSON output is available.
+
+% Copyright © 2019-2020 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/>.
+
+global M_
+
+% Set default value
+if nargin<4 || isempty(noresids)
+    noresids = true;
+end
+
+% Delete outfold subdirectory if it already exists
+if exist(outfold, 'dir')
+    rmdir(outfold, 's');
+end
+
+% Create the subdirectoty where the generated files will be saved.
+mkdir(outfold);
+
+% Check that infile.mod and the related JSON output exist.
+if ~exist(sprintf('%s.mod', infile), 'file')
+    error('Cannot find %s.mod.', infile)
+end
+if ~exist(sprintf('%s/model/json', infile), 'dir')
+    error('Cannot find %s/model/json folder. Did you run %s.mod with the json option?', infile, infile);
+end
+
+% Check if some variables have to be renamed.
+rename = M_.equations_tags(strcmp('rename',M_.equations_tags(:,2)),[1,3]);
+isrename = ~isempty(rename);
+
+if nargin<5
+    % Load json file (original mod file)
+    json = loadjson_(sprintf('%s/model/json/modfile-original.json', M_.dname));
+end
+
+% Create a new file.
+fid = fopen(sprintf('%s/model.inc', outfold), 'w');
+
+plist = {};
+elist = {};
+xlist = {};
+
+for i=1:length(eqtags)
+    rhs = [];
+    lhs = [];
+    % Get equation number.
+    eqnum = get_equation_number_by_tag(eqtags{i}, M_);
+    % Get the original equation.
+    [LHS, RHS] = get_lhs_and_rhs(eqtags{i}, M_, true, json);
+    % Get the parameters, endogenous and exogenous variables in the current equation.
+    [pnames, ~, xnames] = get_variables_and_parameters_in_equation(LHS, RHS, M_);
+    lhs_expression = LHS;
+    LHS = get_variables_and_parameters_in_expression(LHS);
+    enames = LHS;
+    if length(LHS)>1
+        error('Expressions with more than one variable on the LHS are not allowed.')
+    end
+    LHS = LHS{1};
+    if isrename
+        [variable_has_to_be_renamed, id] = ismember(eqnum, [rename{:,1}]);
+        if variable_has_to_be_renamed
+            TMP = strsplit(rename{id,2}, ',');
+            for j=1:length(TMP)
+                tmp = strsplit(TMP{j}, '->');
+                lhs_expression = exactstrrep(lhs_expression, tmp{1}, tmp{2});
+                RHS = exactstrrep(RHS, tmp{1}, tmp{2});
+                rep = strcmp(tmp{1}, enames);
+                if any(rep)
+                    enames(rep) = tmp(2);
+                end
+                rep = strcmp(tmp{1}, xnames);
+                if any(rep)
+                    xnames(rep) = tmp(2);
+                end
+            end
+        end
+    end
+    % Remove residual from equation if required.
+    if noresids
+        exogenous_variables_to_be_removed = ~ismember(xnames, M_.simulation_exo_names);
+        if any(exogenous_variables_to_be_removed)
+            switch sum(exogenous_variables_to_be_removed)
+              case 1
+                RHS = regexprep(RHS, sprintf('(\\ *)(+)(\\ *)%s', xnames{exogenous_variables_to_be_removed}), '');
+                RHS = regexprep(RHS, sprintf('%s', xnames{exogenous_variables_to_be_removed}), '');
+              case 0
+                % Nothing to do.
+              otherwise
+                error('Cannot remove more than one exogenous variable in an equation (%s).', eqtags{i})
+            end
+            xnames = setdiff(xnames, xnames{exogenous_variables_to_be_removed});
+        end
+    end
+    % Unroll expectation terms if any.
+    isvar = regexp(RHS, 'var_expectation\(model_name = (?<name>\w+)\)', 'names');
+    ispac = regexp(RHS, 'pac_expectation\(model_name = (?<name>\w+)\)', 'names');
+    if ~isempty(isvar)
+        rhs = write_expectations(eqtags{i}, isvar.name, 'var');
+        lhs = sprintf('%s_VE', eqtags{i});
+        RHS = strrep(RHS, sprintf('var_expectation(model_name = %s)', isvar.name), lhs);
+    end
+    if ~isempty(ispac)
+        [rhs, growthneutralitycorrection] = write_expectations(eqtags{i}, ispac.name, 'pac');
+        lhs = sprintf('%s_PE', eqtags{i});
+        RHS = strrep(RHS, sprintf('pac_expectation(model_name = %s)', ispac.name), lhs);
+        if ~isempty(growthneutralitycorrection)
+            RHS = sprintf('%s + %s', RHS, growthneutralitycorrection);
+        end
+    end
+    % Print equation for unrolled PAC/VAR-expectation and update
+    % list of parameters and endogenous variables (if any).
+    if ~isempty(rhs)
+        % Note that the call to get_variables_and_parameters_in_equation()
+        % will not return the lhs variable in expectation_enames since
+        % the name is created on the fly and is not a  member of M_.endo_names.
+        expectation_pnames = get_variables_and_parameters_in_equation('', rhs, M_);
+        expectation_enames = get_variables_and_parameters_in_expression(lhs);
+        expectation_xnames = get_variables_and_parameters_in_expression(rhs);
+        pnames = union(pnames, expectation_pnames);
+        xnames = union(xnames, setdiff(expectation_xnames, expectation_pnames));
+        enames = union(enames, expectation_enames);
+        fprintf(fid, '[name=''%s'']\n', lhs);
+        fprintf(fid, '%s = %s;\n\n', lhs, rhs);
+    else
+        pRHS = get_variables_and_parameters_in_equation('', RHS, M_);
+        xRHS = get_variables_and_parameters_in_expression(RHS);
+        xnames = union(xnames, setdiff(xRHS, pRHS));
+        pnames = union(pnames, pRHS);
+    end
+    % Update pnames, enames and xnames if PAC with growth neutrality correction.
+    if ~isempty(ispac) && ~isempty(growthneutralitycorrection)
+        [growthneutralitycorrection_pnames, ...
+             growthneutralitycorrection_enames, ...
+             growthneutralitycorrection_xnames] = get_variables_and_parameters_in_equation('', growthneutralitycorrection, M_);
+        if ~isempty(growthneutralitycorrection_pnames)
+            pnames = union(pnames, growthneutralitycorrection_pnames);
+        end
+        if ~isempty(growthneutralitycorrection_enames)
+            xnames = union(xnames, growthneutralitycorrection_enames);
+        end
+        if ~isempty(growthneutralitycorrection_xnames)
+            xnames = union(xnames, growthneutralitycorrection_xnames);
+        end
+    end
+    % Print tags
+    if iscell(json.model)
+        tfields = fieldnames(json.model{eqnum}.tags);
+        tags = sprintf('%s=''%s''', tfields{1}, json.model{eqnum}.tags.(tfields{1}));
+        for j=2:length(tfields)
+            if ~isempty(json.model{eqnum}.tags.(tfields{j}))
+                tags = sprintf('%s, %s=''%s''', tags, tfields{j}, json.model{eqnum}.tags.(tfields{j}));
+            end
+        end
+    else
+        tfields = fieldnames(json.model.tags);
+        tags = sprintf('%s=''%s''', tfields{1}, json.model.tags.(tfields{1}));
+        for j=2:length(tfields)
+            if ~isempty(json.model.tags.(tfields{j}))
+                tags = sprintf('%s, %s=''%s''', tags, tfields{j}, json.model.tags.(tfields{j}));
+            end
+        end
+    end
+    fprintf(fid, '[%s]\n', tags);
+    % Print equation.
+    fprintf(fid, '%s = %s;\n\n', lhs_expression, RHS);
+    % Update lists of parameters, endogenous variables and exogenous variables.
+    plist = union(plist, pnames);
+    elist = union(elist, enames);
+    xlist = union(xlist, xnames);
+end
+fclose(fid);
+
+% Export parameters
+if ~isempty(plist)
+    fid = fopen(sprintf('%s/parameters.inc', outfold), 'w');
+    fprintf(fid, 'parameters %s;', sprintf('%s ', plist{:}));
+    fclose(fid);
+end
+
+% Export endogegnous variables
+fid = fopen(sprintf('%s/endogenous.inc', outfold), 'w');
+printlistofvariables(fid, 'endo', elist, M_, elist);
+fclose(fid);
+
+% Export exogenous variables
+if ~isempty(xlist)
+    fid = fopen(sprintf('%s/exogenous.inc', outfold), 'w');
+    printlistofvariables(fid, 'exo', xlist, M_, xlist);
+    fclose(fid);
+end
+
+% Export parameter values
+if ~isempty(plist)
+    fid = fopen(sprintf('%s/parameter-values.inc', outfold), 'w');
+    for i=1:length(plist)
+        id = strcmp(plist{i}, M_.param_names);
+        if any(id)
+            fprintf(fid, '%s = %s;\n', plist{i}, num2str(M_.params(id), 16));
+        end
+    end
+    fclose(fid);
+end
+
+function printlistofvariables(fid, kind, list, DynareModel, vappend)
+    if isfield(DynareModel, sprintf('%s_partitions', kind))
+        % Some endogenous variables are tagged.
+        switch kind
+          case 'exo'
+            tfields = fieldnames(DynareModel.exo_partitions);
+            vlist = 'varexo';
+            vnames = DynareModel.exo_names;
+            partitions = DynareModel.exo_partitions;
+          case 'endo'
+            tfields = fieldnames(DynareModel.endo_partitions);
+            vlist = 'var';
+            vnames = DynareModel.endo_names(1:DynareModel.orig_endo_nbr);
+            partitions = DynareModel.endo_partitions;
+          otherwise
+            error('Illegal value for second input argument.')
+        end
+        for i = 1:length(list)
+            id = strmatch(list{i}, vnames, 'exact');
+            if ~isempty(id)
+                tags = '';
+                for j=1:length(tfields)
+                    if ~isempty(partitions.(tfields{j}){id})
+                        tags = sprintf('%s, %s=''%s''', tags, tfields{j}, partitions.(tfields{j}){id});
+                    end
+                end
+                if ~isempty(tags)
+                    tags = sprintf('(%s)', tags(3:end));
+                end
+            elseif ~isempty(strmatch(list{i}, vappend, 'exact'))
+                % Nothing to do, this variable was renamed by cherrypick
+                tags = '';
+            else
+                if isequal(kind, 'endo') &&  (isequal(list{i}(end-2:end), '_PE') || isequal(list{i}(end-2:end), '_VE'))
+                    if isequal(list{i}(end-2:end), '_PE')
+                        tags = sprintf('(expectation_kind=''%s'')', 'pac');
+                    else
+                        tags = sprintf('(expectation_kind=''%s'')', 'var');
+                    end
+                else
+                    error('Unknown variable.')
+                end
+            end
+            if isempty(tags)
+                vlist = sprintf('%s\n\t%s', vlist, list{i});
+            else
+                vlist = sprintf('%s\n\t%s %s', vlist, list{i}, tags);
+            end
+        end
+        fprintf(fid, '%s;', vlist);
+    else
+        switch kind
+          case 'exo'
+            vlist = 'varexo';
+          case 'endo'
+            vlist = 'var';
+          otherwise
+            error('Illegal value for second input argument.')
+        end
+        for i=1:length(list)
+            vlist = sprintf('%s\n\t%s', vlist, list{i});
+        end
+        fprintf(fid, '%s;', vlist);
+    end
\ No newline at end of file
diff --git a/matlab/cli/estimate.m b/matlab/cli/estimate.m
new file mode 100644
index 0000000000000000000000000000000000000000..e94aa549beca8a6dbe21b2a0c1c7c5daca5e499c
--- /dev/null
+++ b/matlab/cli/estimate.m
@@ -0,0 +1,61 @@
+function estimate(method, data, varargin)
+    
+% Copyright (C) 2017 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/>.
+global M_
+
+% Check first input.
+if ~ischar(method) || isempty(regexp(method, 'method\(((?=[\w])[^_0-9][\w]*)\)', 'match'))
+    error('estimate:: First argument must be an estimation method')
+end
+
+% Check second input argument.
+if ~ischar(data) || isempty(regexp(data, 'data\(((?=[\w])[^_0-9][\w]*)\)', 'match'))
+    error('estimate:: Second argument must be a data option.')
+end
+
+% Get the estimation method.
+tmp = regexp(method, 'method\(((?=[\w])[^_0-9][\w]*)\)', 'tokens');
+method = tmp{1}{1};
+
+% Get the data.
+tmp = regexp(data, 'data\(((?=[\w])[^_0-9][\w]*)\)', 'tokens');
+ds = tmp{1}{1};
+if ismember(ds, evalin('caller','who'))
+    ts = evalin('caller', ds); 
+    if ~isdseries(ts)
+        error('estimate:: %s has to be a dseries object!', ds)
+    end
+else
+    error('estimate:: %s is unknown!', ds)
+end
+
+eqns = varargin(:);
+nqns = length(varargin);
+
+% Run estimations
+for i=1:nqns
+    if ~ismember(eqns{i}, M_.equations_tags(strmatch('name', M_.equations_tags(:,2)),3))
+        error('estimate:: There is no equation named as %s!', eqns{i})
+    end
+    switch method
+      case 'ols'
+        olseqs(ts, eqns{i});
+      otherwise
+        error('estimate:: Unknown estimation method')
+    end
+end
\ No newline at end of file
diff --git a/matlab/convertjsondecode.m b/matlab/convertjsondecode.m
new file mode 100644
index 0000000000000000000000000000000000000000..deff8cf6a9926e35d19addf466c4487999cd2728
--- /dev/null
+++ b/matlab/convertjsondecode.m
@@ -0,0 +1,45 @@
+function o = convertjsondecode(o)
+
+% Converts the output of jsondecode to be consistent with the output of loadjson.
+%
+% INPUTS
+% - o     [struct]      Output of jsondecode.
+%
+% OUTPUTS
+% - o     [struct]      Converted output of jsondecode.
+%
+% REMARKS
+% The fields returned by the loadjson are systematically cell
+% array, while jsondecode returns structure arrays if
+% possible. This routine reorganize the data consistently with
+% loadjson.
+
+% Copyright (C) 2020 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/>.
+
+fnames = fieldnames(o);
+
+for i=1:length(fnames)
+    tmp = o.(fnames{i});
+    if isstruct(tmp) && length(tmp)>1
+        TMP = cell(length(tmp), 1);
+        for j=1:length(tmp)
+            TMP{j} = tmp(j);
+        end
+        o.(fnames{i}) = TMP;
+    end
+end
\ No newline at end of file
diff --git a/matlab/default_option_values.m b/matlab/default_option_values.m
index 0254bcf24886e926ac710987739239492f53de74..66ba29f1389967b5beeb925d481730059a450dec 100644
--- a/matlab/default_option_values.m
+++ b/matlab/default_option_values.m
@@ -740,4 +740,7 @@ options_.figures.textwidth=0.8;
 
 options_.varobs_id=[]; %initialize field
 
+options_.pac.estimation.ols.share_of_optimizing_agents.lb = 0.0;
+options_.pac.estimation.ols.share_of_optimizing_agents.ub = 1.0;
+
 end
diff --git a/matlab/dyn_table.m b/matlab/dyn_table.m
new file mode 100644
index 0000000000000000000000000000000000000000..3e871c125ef9ab76c4797f6387856e50c16cea70
--- /dev/null
+++ b/matlab/dyn_table.m
@@ -0,0 +1,96 @@
+function dyn_table(title, preamble, afterward, rows, cols, indent, data)
+%function dyn_table(title, rows, cols, indent, data)
+% Print Table
+%
+% INPUTS
+%   title      [char]
+%   preamble   [cell string]
+%   afterward  [cell string]
+%   rows       [cell string]
+%   cols       [cell string]
+%   indent     [integer]
+%   data       [matrix]
+%
+% OUTPUTS
+%   None
+%
+% SPECIAL REQUIREMENTS
+%   none
+
+% Copyright (C) 2017-2019 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/>.
+
+assert(ischar(title), 'title must be a char')
+assert(iscellstr(preamble) && iscellstr(afterward) && iscellstr(rows) && iscellstr(cols), ...
+    'preamble, afterward, rows, and cols must be cell arrays of strings')
+assert(size(data, 1) == length(rows), 'must have the same number of rows')
+assert(size(data, 2) == length(cols), 'must have the same number of columns')
+assert(isint(indent), 'indent must be an integer')
+
+skipline(3)
+
+%% Print Output
+rowstrlens = cellfun(@length, rows);
+colstrlens = cellfun(@length, cols);
+maxrowstrlen = max(rowstrlens);
+
+colbegin = repmat(' ', 1, 2*indent + maxrowstrlen);
+colrow = sprintf('%s', colbegin);
+colrow2 = colrow;
+format = ['    %-' num2str(maxrowstrlen) 's'];
+for i = 1:length(cols)
+    field_width = 16;
+    if colstrlens(i) < field_width
+        colrow = [colrow repmat(' ', 1, floor((field_width-mod(colstrlens(i), field_width))/2)) cols{i} repmat(' ', 1, ceil((field_width-mod(colstrlens(i), field_width))/2))];
+        colrow2 = [colrow2 repmat('_', 1, field_width)];
+    else
+        colrow = [colrow cols{i}];
+        colrow2 = [colrow2 repmat('_', 1, colstrlens(i))];
+        field_width = colstrlens(i);
+    end
+    if i ~= length(cols)
+        colrow = [colrow repmat(' ', 1, indent)];
+        colrow2 = [colrow2 repmat(' ', 1, indent)];
+    end
+    format = [format repmat(' ', 1, indent) '%' sprintf('%d.5g', field_width)];
+end
+
+% Center title
+if length(title) >= length(colrow)
+    fprintf('%s\n\n', title)
+else
+    fprintf('%s%s\n\n', repmat(' ', 1, floor((length(colrow)+indent-length(title))/2)), title);
+end
+spaces = repmat(' ', 1, indent);
+for i = 1:length(preamble)
+    fprintf('%s%s\n', spaces, preamble{i});
+end
+
+fprintf('%s\n', colrow);
+fprintf('%s\n\n', colrow2);
+
+format = [format '\n'];
+for i = 1:length(rows)
+    fprintf(format, rows{i}, data(i, :));
+end
+
+fprintf('\n');
+for i = 1:length(afterward)
+    fprintf('%s%s\n', spaces, afterward{i});
+end
+
+fprintf('%s\n\n', repmat('_', 1, length(colrow2)));
diff --git a/matlab/dynare_config.m b/matlab/dynare_config.m
index 6e0442d8c39496c6d0482dd2dc9455563970eb1b..f54506f4fa41734cfce21cf7dac064297773b72a 100644
--- a/matlab/dynare_config.m
+++ b/matlab/dynare_config.m
@@ -61,6 +61,8 @@ p = {'/distributions/' ; ...
      '/cli/' ; ...
      '/lmmcp/' ; ...
      '/optimization/' ; ...
+     '/ols/' ; ...
+     '/pac-tools/' ; ...
      '/method_of_moments/' ; ...
      '/discretionary_policy/' ; ...
      '/accessors/' ; ...
diff --git a/matlab/dynare_solve.m b/matlab/dynare_solve.m
index 37483e46f2f01fe0ade417a48c32efc0cbae5f9f..b27e3d91eb7109dd99c97e496af5931e38860858 100644
--- a/matlab/dynare_solve.m
+++ b/matlab/dynare_solve.m
@@ -1,23 +1,21 @@
-function [x,info,fvec,fjac] = dynare_solve(func,x,options,varargin)
-% function [x,info,fvec,fjac] = dynare_solve(func,x,options,varargin)
-% proposes different solvers
+function [x, errorflag, fvec, fjac] = dynare_solve(f, x, options, varargin)
+
+% Solves a nonlinear system of equations, f(x) = 0 with n unknowns
+% and n equations.
 %
 % INPUTS
-%    func:             name of the function to be solved
-%    x:                guess values
-%    options:          struct of Dynare options
-%    varargin:         list of arguments following jacobian_flag
+% - f            [char, fhandle]    function to be solved
+% - x            [double]           n×1 vector, initial guess.
+% - options      [struct]           Dynare options, aka options_.
+% - varargin                        list of additional arguments to be passed to func.
 %
 % OUTPUTS
-%    x:                solution
-%    info=1:           the model can not be solved
-%    fvec:             Function value (used for debugging when check=1)
-%    fjac:             Jacobian (used for debugging when check=1)
-%
-% SPECIAL REQUIREMENTS
-%    none
+% - x            [double]           n×1 vector, solution.
+% - errorflag    [logical]          scalar, true iff the model can not be solved.
+% - fvec         [double]           n×1 vector, function value at x (f(x), used for debugging when errorflag is true).
+% - fjac         [double]           n×n matrix, Jacobian value at x (J(x), used for debugging when errorflag is true).
 
-% Copyright (C) 2001-2017 Dynare Team
+% Copyright © 2001-2020 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -34,14 +32,12 @@ function [x,info,fvec,fjac] = dynare_solve(func,x,options,varargin)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
 
-% jacobian_flag=true:  jacobian given by the 'func' function
-% jacobian_flag=false:  jacobian obtained numerically
-jacobian_flag = options.jacobian_flag;
+jacobian_flag = options.jacobian_flag; % true iff Jacobian is returned by f routine (as a second output argument).
 
 % Set tolerance parameter depending the the caller function.
 stack = dbstack;
 if isoctave
-    [pathstr,name,ext]=fileparts(stack(2).file);
+    [~, name, ext]=fileparts(stack(2).file);
     caller_file_name=[name,ext];
 else
     caller_file_name=stack(2).file;
@@ -60,7 +56,7 @@ else
     maxit = options.steady.maxit;
 end
 
-info = 0;
+errorflag = false;
 nn = size(x,1);
 
 % Get status of the initial guess (default values?)
@@ -74,9 +70,20 @@ else
     in0 = nn;
 end
 
+% Get first element of varargin if solve_algo ∈ {12,14} and rename varargin.
+if ismember(options.solve_algo, [12, 14])
+    isloggedlhs = varargin{1};
+    isauxdiffloggedrhs = varargin{2};
+    endo_names = varargin{3};
+    lhs = varargin{4};
+    arguments = varargin(5:end);
+else
+    arguments = varargin;
+end
+
 % checking initial values
 if jacobian_flag
-    [fvec, fjac] = feval(func, x, varargin{:});
+    [fvec, fjac] = feval(f, x, arguments{:});
     wrong_initial_guess_flag = false;
     if ~all(isfinite(fvec)) || any(isinf(fjac(:))) || any(isnan((fjac(:)))) ...
             || any(~isreal(fvec)) || any(~isreal(fjac(:)))
@@ -92,7 +99,7 @@ if jacobian_flag
         while wrong_initial_guess_flag && tentative_number<=in0*10
             tentative_number = tentative_number+1;
             x(idx) = rand(in0, 1)*10;
-            [fvec, fjac] = feval(func, x, varargin{:});
+            [fvec, fjac] = feval(f, x, arguments{:});
             wrong_initial_guess_flag = ~all(isfinite(fvec)) || any(isinf(fjac(:))) || any(isnan((fjac(:))));
         end
         % If all previous attempts failed, try with real numbers.
@@ -100,7 +107,7 @@ if jacobian_flag
         while wrong_initial_guess_flag && tentative_number<=in0*10
             tentative_number = tentative_number+1;
             x(idx) = randn(in0, 1)*10;
-            [fvec, fjac] = feval(func, x, varargin{:});
+            [fvec, fjac] = feval(f, x, arguments{:});
             wrong_initial_guess_flag = ~all(isfinite(fvec)) || any(isinf(fjac(:))) || any(isnan((fjac(:))));
         end
         % Last tentative, ff all previous attempts failed, try with negative numbers.
@@ -108,13 +115,13 @@ if jacobian_flag
         while wrong_initial_guess_flag && tentative_number<=in0*10
             tentative_number = tentative_number+1;
             x(idx) = -rand(in0, 1)*10;
-            [fvec, fjac] = feval(func, x, varargin{:});
+            [fvec, fjac] = feval(f, x, arguments{:});
             wrong_initial_guess_flag = ~all(isfinite(fvec)) || any(isinf(fjac(:))) || any(isnan((fjac(:))));
         end
     end
 else
-    fvec = feval(func,x,varargin{:});
-    fjac = zeros(nn,nn);
+    fvec = feval(f, x, arguments{:});
+    fjac = zeros(nn, nn);
     wrong_initial_guess_flag = false;
     if ~all(isfinite(fvec))
         % Let's try random numbers for the variables initialized with the default value.
@@ -124,7 +131,7 @@ else
         while wrong_initial_guess_flag && tentative_number<=in0*10
             tentative_number = tentative_number+1;
             x(idx) = rand(in0, 1)*10;
-            fvec = feval(func, x, varargin{:});
+            fvec = feval(f, x, arguments{:});
             wrong_initial_guess_flag = ~all(isfinite(fvec));
         end
         % If all previous attempts failed, try with real numbers.
@@ -132,7 +139,7 @@ else
         while wrong_initial_guess_flag && tentative_number<=in0*10
             tentative_number = tentative_number+1;
             x(idx) = randn(in0, 1)*10;
-            fvec = feval(func, x, varargin{:});
+            fvec = feval(f, x, arguments{:});
             wrong_initial_guess_flag = ~all(isfinite(fvec));
         end
         % Last tentative, ff all previous attempts failed, try with negative numbers.
@@ -140,7 +147,7 @@ else
         while wrong_initial_guess_flag && tentative_number<=in0*10
             tentative_number = tentative_number+1;
             x(idx) = -rand(in0, 1)*10;
-            fvec = feval(func, x, varargin{:});
+            fvec = feval(f, x, arguments{:});
             wrong_initial_guess_flag = ~all(isfinite(fvec));
         end
     end
@@ -148,7 +155,7 @@ end
 
 % Exit with error if no initial guess has been found.
 if wrong_initial_guess_flag
-    info=1;
+    errorflag = true;
     x = NaN(size(fvec));
     return
 end
@@ -180,108 +187,156 @@ if options.solve_algo == 0
         options4fsolve.Jacobian = 'off';
     end
     if ~isoctave
-        [x,fval,exitval,output] = fsolve(func,x,options4fsolve,varargin{:});
+        [x, ~, exitval] = fsolve(f, x, options4fsolve, arguments{:});
     else
         % Under Octave, use a wrapper, since fsolve() does not have a 4th arg
-        if ischar(func)
-            func2 = str2func(func);
+        if ischar(f)
+            f2 = str2func(f);
         else
-            func2 = func;
+            f2 = f;
         end
-        func = @(x) func2(x, varargin{:});
+        f = @(x) f2(x, arguments{:});
         % The Octave version of fsolve does not converge when it starts from the solution
-        fvec = feval(func,x);
+        fvec = feval(f, x);
         if max(abs(fvec)) >= tolf
-            [x,fval,exitval,output] = fsolve(func,x,options4fsolve);
+            [x, ~,exitval] = fsolve(f, x, options4fsolve);
         else
             exitval = 3;
         end
     end
 
     if exitval == 1
-        info = 0;
+        errorflag = false;
     elseif exitval > 1
-        if ischar(func)
-            func2 = str2func(func);
+        if ischar(f)
+            f2 = str2func(f);
         else
-            func2 = func;
+            f2 = f;
         end
-        func = @(x) func2(x, varargin{:});
-        fvec = feval(func,x);
+        f = @(x) f2(x, arguments{:});
+        fvec = feval(f, x);
         if max(abs(fvec)) >= tolf
-            info = 1;
+            errorflag = true;
         else
-            info = 0;
+            errorflag = false;
         end
     else
-        info = 1;
+        errorflag = true;
     end
-elseif options.solve_algo == 1
-    [x,info]=solve1(func,x,1:nn,1:nn,jacobian_flag,options.gstep, ...
-                    tolf,tolx, ...
-                    maxit,options.debug,varargin{:});
-elseif options.solve_algo == 9
-    [x,info]=trust_region(func,x,1:nn,1:nn,jacobian_flag,options.gstep, ...
-                          tolf,tolx, ...
-                          maxit,options.debug,varargin{:});
-elseif options.solve_algo == 2 || options.solve_algo == 4
-
-    if options.solve_algo == 2
+elseif options.solve_algo==1
+    [x, errorflag] = solve1(f, x, 1:nn, 1:nn, jacobian_flag, options.gstep, ...
+                       tolf, tolx, ...
+                       maxit, options.debug, arguments{:});
+elseif options.solve_algo==9
+    [x, errorflag] = trust_region(f, x, 1:nn, 1:nn, jacobian_flag, options.gstep, ...
+                             tolf, tolx, ...
+                             maxit, options.debug, arguments{:});
+elseif ismember(options.solve_algo, [2, 12, 4])
+    if ismember(options.solve_algo, [2, 12])
         solver = @solve1;
     else
         solver = @trust_region;
     end
-
+    specializedunivariateblocks = options.solve_algo == 12;
     if ~jacobian_flag
         fjac = zeros(nn,nn) ;
-        dh = max(abs(x),options.gstep(1)*ones(nn,1))*eps^(1/3);
+        dh = max(abs(x), options.gstep(1)*ones(nn,1))*eps^(1/3);
         for j = 1:nn
             xdh = x ;
             xdh(j) = xdh(j)+dh(j) ;
-            fjac(:,j) = (feval(func,xdh,varargin{:}) - fvec)./dh(j) ;
+            fjac(:,j) = (feval(f, xdh, arguments{:})-fvec)./dh(j) ;
         end
     end
-
     [j1,j2,r,s] = dmperm(fjac);
-
+    JAC = abs(fjac(j1,j2))>0;
     if options.debug
-        disp(['DYNARE_SOLVE (solve_algo=2|4): number of blocks = ' num2str(length(r))]);
+        disp(['DYNARE_SOLVE (solve_algo=2|4|12): number of blocks = ' num2str(length(r)-1)]);
     end
-
+    l = 0;
+    fre = false;
     for i=length(r)-1:-1:1
+        blocklength = r(i+1)-r(i);
         if options.debug
-            disp(['DYNARE_SOLVE (solve_algo=2|4): solving block ' num2str(i) ', of size ' num2str(r(i+1)-r(i)) ]);
+            dprintf('DYNARE_SOLVE (solve_algo=2|4|12): solving block %u of size %u.', i, blocklength);
+        end
+        j = r(i):r(i+1)-1;
+        if specializedunivariateblocks
+            if options.debug
+                dprintf('DYNARE_SOLVE (solve_algo=2|4|12): solving block %u by evaluating RHS.', i);
+            end
+            if isequal(blocklength, 1)
+                if i<length(r)-1
+                    if fre || any(JAC(r(i), s(i)+(1:l)))
+                        % Reevaluation of the residuals is required because the current RHS depends on
+                        % variables that potentially have been updated previously.
+                        z = feval(f, x, arguments{:});
+                        l = 0;
+                        fre = false;
+                    end
+                else
+                    % First iteration requires the evaluation of the residuals.
+                    z = feval(f, x, arguments{:});
+                end
+                l = l+1;
+                if isequal(lhs{j1(j)}, endo_names{j2(j)}) || isequal(lhs{j1(j)}, sprintf('log(%s)', endo_names{j2(j)}))
+                    if isloggedlhs(j1(j))
+                        x(j2(j)) = exp(log(x(j2(j)))-z(j1(j)));
+                    else
+                        x(j2(j)) = x(j2(j))-z(j1(j));
+                    end
+                else
+                    if options.debug
+                        dprintf('LHS variable is not determined by RHS expression (%u).', j1(j))
+                        dprintf('%s -> %s', lhs{j1(j)}, endo_names{j2(j)})
+                    end
+                    if ~isempty(regexp(lhs{j1(j)}, '\<AUX_DIFF_(\d*)\>', 'once'))
+                        if isauxdiffloggedrhs(j1(j))
+                            x(j2(j)) = exp(log(x(j2(j)))+z(j1(j)));
+                        else
+                            x(j2(j)) = x(j2(j))+z(j1(j));
+                        end
+                    else
+                        error('Algorithm solve_algo=%u cannot be used with this nonlinear problem.', options.solve_algo)
+                    end
+                end
+                continue
+            end
+        else
+            if options.debug
+                dprintf('DYNARE_SOLVE (solve_algo=2|4|12): solving block %u with trust_region routine.', i);
+            end
         end
-        [x,info]=solver(func,x,j1(r(i):r(i+1)-1),j2(r(i):r(i+1)-1),jacobian_flag, ...
-                        options.gstep, ...
-                        tolf,tolx, ...
-                        maxit,options.debug,varargin{:});
-        if info
+        [x, errorflag] = solver(f, x, j1(j), j2(j), jacobian_flag, ...
+                                options.gstep, ...
+                                tolf, options.solve_tolx, ...
+                                maxit, options.debug, arguments{:});
+        fre = true;
+        if errorflag
             return
         end
     end
-    fvec = feval(func,x,varargin{:});
-    if max(abs(fvec)) > tolf
-        [x,info]=solver(func,x,1:nn,1:nn,jacobian_flag, ...
-                        options.gstep, tolf,tolx, ...
-                        maxit,options.debug,varargin{:});
+    fvec = feval(f, x, arguments{:});
+    if max(abs(fvec))>tolf
+        disp('Call solver on the full nonlinear problem.')
+        [x, errorflag] = solver(f, x, 1:nn, 1:nn, jacobian_flag, ...
+                                options.gstep, tolf, options.solve_tolx, ...
+                                maxit, options.debug, arguments{:});
     end
-elseif options.solve_algo == 3
+elseif options.solve_algo==3
     if jacobian_flag
-        [x,info] = csolve(func,x,func,1e-6,500,varargin{:});
+        [x, errorflag] = csolve(f, x, f, 1e-6, 500, arguments{:});
     else
-        [x,info] = csolve(func,x,[],1e-6,500,varargin{:});
+        [x, errorflag] = csolve(f, x, [], 1e-6, 500, arguments{:});
     end
-    [fvec, fjac] = feval(func, x, varargin{:});
-elseif options.solve_algo == 10
+    [fvec, fjac] = feval(f, x, arguments{:});
+elseif options.solve_algo==10
     % LMMCP
     olmmcp = options.lmmcp;
-
-    [x,fval,exitflag] = lmmcp(func,x,olmmcp.lb,olmmcp.ub,olmmcp,varargin{:});
-    if exitflag == 1
-        info = 0;
+    [x, ~, exitflag] = lmmcp(f, x, olmmcp.lb, olmmcp.ub, olmmcp, arguments{:});
+    if exitflag==1
+        errorflag = false;
     else
-        info = 1;
+        errorflag = true;
     end
 elseif options.solve_algo == 11
     % PATH mixed complementary problem
@@ -293,14 +348,26 @@ elseif options.solve_algo == 11
     end
     omcppath = options.mcppath;
     global mcp_data
-    mcp_data.func = func;
-    mcp_data.args = varargin;
-    info=0;
+    mcp_data.func = f;
+    mcp_data.args = arguments;
     try
-        [x,fval,jac,mu] = pathmcp(x,omcppath.lb,omcppath.ub,'mcp_func',omcppath.A,omcppath.b,omcppath.t,omcppath.mu0);
+        [x, fval, jac, mu] = pathmcp(x,omcppath.lb,omcppath.ub,'mcp_func',omcppath.A,omcppath.b,omcppath.t,omcppath.mu0);
     catch
-        info = 1;
+        errorflag = true;
+    end
+elseif ismember(options.solve_algo, [13, 14])
+    if ~jacobian_flag
+        error('DYNARE_SOLVE: option solve_algo=13|14 needs computed Jacobian')
+    end
+    auxstruct = struct();
+    if options.solve_algo == 14
+        auxstruct.lhs = lhs;
+        auxstruct.endo_names = endo_names;
+        auxstruct.isloggedlhs = isloggedlhs;
+        auxstruct.isauxdiffloggedrhs = isauxdiffloggedrhs;
     end
+    [x, errorflag] = block_trust_region(f, x, tolf, options.solve_tolx, maxit, options.debug, auxstruct, arguments{:});
+    [fvec, fjac] = feval(f, x, arguments{:});
 else
-    error('DYNARE_SOLVE: option solve_algo must be one of [0,1,2,3,4,9,10,11]')
+    error('DYNARE_SOLVE: option solve_algo must be one of [0,1,2,3,4,9,10,11,12,13,14]')
 end
diff --git a/matlab/exactcontains.m b/matlab/exactcontains.m
new file mode 100644
index 0000000000000000000000000000000000000000..8b78e7b2999bb8a86a03c5ed0c01733c3c1f9e17
--- /dev/null
+++ b/matlab/exactcontains.m
@@ -0,0 +1,22 @@
+function b = exactcontains(str, word)
+
+% Same as contains but with exact word matching.
+
+% Copyright (C) 2019 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/>.
+
+b = ~isempty(regexp(str, sprintf('\\<%s\\>', word)));
\ No newline at end of file
diff --git a/matlab/exactstrrep.m b/matlab/exactstrrep.m
new file mode 100644
index 0000000000000000000000000000000000000000..eed76ddb102d5d1a780afbc2ed276371aec396be
--- /dev/null
+++ b/matlab/exactstrrep.m
@@ -0,0 +1,22 @@
+function str = exactstrrep(str, old, new)
+
+% Same as strrep but with exact word matching.
+
+% Copyright (C) 2019 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/>.
+
+str = regexprep(str, ['\<', old,'\>'], new);
\ No newline at end of file
diff --git a/matlab/get_ar_ec_matrices.m b/matlab/get_ar_ec_matrices.m
new file mode 100644
index 0000000000000000000000000000000000000000..6831edc56ec2d5f4053759bd1e38b71e02e9f1b4
--- /dev/null
+++ b/matlab/get_ar_ec_matrices.m
@@ -0,0 +1,292 @@
+function get_ar_ec_matrices(model_name, model_type)
+%function get_ar_ec_matrices(model_name, model_type)
+%
+% Returns the autoregressive matrix associated with the auxiliary model specified by
+% model_name. Output is stored in cellarray oo_.(model_type).(model_name).ar,
+% with oo_.(model_type).(model_name).ar(:,:,i) being the AR matrix at time t-i. Each
+% AR matrix is stored with rows and columns organized by the ordering of the
+% equation tags found in M_.(model_type).(model_name).eqtags.
+% oo_.(model_type).(model_name).ec contains those entries that are not
+% autoregressive.
+%
+% INPUTS
+%
+%   model_name   [string]        the name of the auxiliary model
+%   model_type   [string]        the type of the auxiliary model ('var' or
+%                                'trend_component'. If not passed, the
+%                                value is set by the function; if a 'var'
+%                                subfield is found, that is used. Otherwise
+%                                'trend_component' is used (if it exists as
+%                                a subfield of M_.
+%
+% OUTPUTS
+%
+%   NONE
+
+% Copyright (C) 2018 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/>.
+
+global M_ oo_
+
+%% Check inputs
+assert(nargin <= 2, 'This function requires one or two arguments');
+assert(~isempty(model_name) && ischar(model_name), ...
+    'The first argument must be a non-empty string');
+
+if nargin < 2
+    model_type = 'var';
+    if ~(isfield(M_, model_type) && isfield(M_.(model_type), model_name))
+        model_type = 'trend_component';
+        if ~(isfield(M_, model_type) && isfield(M_.(model_type), model_name))
+            error(['Could not find ' model_name ' in M_.var or ' ...
+                'M_.trend_component. First declare it via the var_model ' ...
+                'or trend_component_model statement.']);
+        end
+    end
+else
+    assert(~isempty(model_type) && ischar(model_type), ...
+        'If provided, the second argument must be a non-empty string');
+    if ~(isfield(M_, model_type) && isfield(M_.(model_type), model_name))
+        error(['Could not find M_.' model_type '.' model_name ...
+            '. First declare it via the var_model or ' ...
+            'trend_component_model statement.']);
+    end
+end
+
+%% Call Dynamic Function
+[junk, g1] = feval([M_.fname '.dynamic'], ...
+    ones(max(max(M_.lead_lag_incidence)), 1), ...
+    ones(1, M_.exo_nbr), ...
+    M_.params, ...
+    zeros(M_.endo_nbr, 1), ...
+    1);
+
+% Choose rows of Jacobian based on equation tags
+ntags = length(M_.(model_type).(model_name).eqtags);
+g1rows = zeros(ntags, 1);
+for i = 1:ntags
+    idxs = strcmp(M_.equations_tags(:, 3), M_.(model_type).(model_name).eqtags{i});
+    if any(idxs)
+        g1rows(i) = M_.equations_tags{idxs, 1};
+    end
+end
+g1 = -1 * g1(g1rows, :);
+
+% Check for leads
+if rows(M_.lead_lag_incidence) == 3
+    idxs = M_.lead_lag_incidence(3, M_.lead_lag_incidence(3, :) ~= 0);
+    assert(~any(any(g1(g1rows, idxs))), ...
+        ['You cannot have leads in the equations specified by ' strjoin(M_.(model_type).(model_name).eqtags, ',')]);
+end
+
+%% Organize AR & EC matrices
+assert(length(M_.(model_type).(model_name).lhs) == rows(g1));
+
+% Find RHS vars for AR & EC matrices
+ecRhsVars = [];
+lhs       = M_.(model_type).(model_name).lhs;
+rhsvars   = cell(length(lhs), 1);
+for i = 1:length(M_.(model_type).(model_name).rhs.vars_at_eq)
+    vars = M_.(model_type).(model_name).rhs.vars_at_eq{i}.var;
+    rhsvars{i}.vars = vars;
+    rhsvars{i}.lags = M_.(model_type).(model_name).rhs.vars_at_eq{i}.lag;
+    rhsvars{i}.arRhsIdxs = [];
+    rhsvars{i}.ecRhsIdxs = [];
+    rhsvars{i}.ecRhsVars = [];
+    for j = 1:length(vars)
+        if vars(j) <= M_.orig_endo_nbr
+            % vars(j) is not an aux var
+            if ismember(vars(j), lhs)
+                rhsvars{i}.arRhsIdxs = [rhsvars{i}.arRhsIdxs find(lhs == vars(j))];
+                rhsvars{i}.ecRhsIdxs = [rhsvars{i}.ecRhsIdxs -1];
+                rhsvars{i}.ecRhsVars = [rhsvars{i}.ecRhsVars -1];
+            else
+                ecRhsVars = union(ecRhsVars, vars(j));
+                rhsvars{i}.ecRhsVars = [rhsvars{i}.ecRhsVars vars(j)];
+                rhsvars{i}.arRhsIdxs = [rhsvars{i}.arRhsIdxs -1];
+                rhsvars{i}.ecRhsIdxs = [rhsvars{i}.ecRhsIdxs find(rhsvars{i}.ecRhsVars == vars(j))];
+            end
+        else
+            % Search aux vars for matching lhs var
+            lhsvaridx = findLhsInAuxVar(vars(j), lhs);
+            if lhsvaridx >= 1
+                rhsvars{i}.arRhsIdxs = [rhsvars{i}.arRhsIdxs find(lhs == lhsvaridx)];
+                rhsvars{i}.ecRhsIdxs = [rhsvars{i}.ecRhsIdxs -1];
+                rhsvars{i}.ecRhsVars = [rhsvars{i}.ecRhsVars -1];
+            else
+                % otherwise find endog that corresponds to this aux var
+                varidx = findVarNoLag(vars(j));
+                ecRhsVars = union(ecRhsVars, varidx);
+                rhsvars{i}.ecRhsVars = [rhsvars{i}.ecRhsVars varidx];
+                rhsvars{i}.arRhsIdxs = [rhsvars{i}.arRhsIdxs -1];
+                rhsvars{i}.ecRhsIdxs = [rhsvars{i}.ecRhsIdxs find(rhsvars{i}.ecRhsVars == varidx)];
+            end
+        end
+    end
+end
+
+[rhsvars, ecRhsVars] = reorderECvars(rhsvars, ecRhsVars, lhs);
+
+% Initialize matrices
+oo_.(model_type).(model_name).ar = zeros(length(lhs), length(lhs), max(M_.(model_type).(model_name).max_lag));
+oo_.(model_type).(model_name).ec = zeros(length(lhs), length(ecRhsVars), 1);
+oo_.(model_type).(model_name).ar_idx = lhs;
+oo_.(model_type).(model_name).ec_idx = ecRhsVars;
+
+% Fill matrices
+for i = 1:length(lhs)
+    for j = 1:length(rhsvars{i}.vars)
+        var = rhsvars{i}.vars(j);
+        if rhsvars{i}.lags(j) == -1
+            g1col = M_.lead_lag_incidence(1, var);
+        else
+            g1col = M_.lead_lag_incidence(2, var);
+        end
+        if g1col ~= 0 && any(g1(:, g1col))
+            if rhsvars{i}.arRhsIdxs(j) > 0
+                % Fill AR
+                [lag, ndiffs] = findLagForVar(var, -rhsvars{i}.lags(j), 0, lhs);
+                oo_.(model_type).(model_name).ar(i, rhsvars{i}.arRhsIdxs(j), lag) = ...
+                    oo_.(model_type).(model_name).ar(i, rhsvars{i}.arRhsIdxs(j), lag) + g1(i, g1col);
+            elseif rhsvars{i}.ecRhsIdxs(j) > 0
+                % Fill EC
+                [lag, ndiffs] = findLagForVar(var, -rhsvars{i}.lags(j), 0, ecRhsVars);
+                if lag==1
+                    if size(oo_.(model_type).(model_name).ec, 3) < lag
+                        oo_.(model_type).(model_name).ec(i, rhsvars{i}.ecRhsIdxs(j), lag) = 0;
+                    end
+                    oo_.(model_type).(model_name).ec(i, rhsvars{i}.ecRhsIdxs(j), lag) = ...
+                        oo_.(model_type).(model_name).ec(i, rhsvars{i}.ecRhsIdxs(j), lag) + g1(i, g1col);
+                end
+            else
+                error('Shouldn''t arrive here');
+            end
+        end
+    end
+end
+end
+
+
+function [rhsvars, ecRhsVarsReordered] = reorderECvars(rhsvars, ecRhsVars, lhs)
+
+global M_
+
+ecRhsVarsReordered = [];
+for i = 1:length(lhs)
+    av = M_.aux_vars([M_.aux_vars.endo_index] == lhs(i));
+    if ~isempty(av)
+        var = ecRhsVars(ecRhsVars == av.orig_index);
+        if ~isempty(var)
+            ecRhsVarsReordered = [ecRhsVarsReordered var];
+             for j = 1:length(rhsvars)
+                 rhsidx = find(rhsvars{j}.ecRhsVars == var);
+                 if ~isempty(rhsidx)
+                     rhsvars{j}.ecRhsIdxs(rhsidx) = length(ecRhsVarsReordered);
+                 end
+             end
+        end
+    end
+end
+end
+
+
+function lhsvaridx = findLhsInAuxVar(auxVar, lhsvars)
+
+global M_
+
+if auxVar <= M_.orig_endo_nbr
+    lhsvaridx = -1;
+    return
+end
+
+av = M_.aux_vars([M_.aux_vars.endo_index] == auxVar);
+
+if av.type == 8 || av.type == 10
+    if ismember(av.endo_index, lhsvars)
+        lhsvaridx = av.endo_index;
+    else
+        lhsvaridx = findLhsInAuxVar(av.orig_index, lhsvars);
+    end
+else
+    if ismember(av.orig_index, lhsvars)
+        lhsvaridx = av.orig_index;
+    else
+        lhsvaridx = findLhsInAuxVar(av.orig_index, lhsvars);
+    end
+end
+end
+
+
+
+function idx = findVarNoLag(auxVar)
+
+global M_
+
+if auxVar <= M_.orig_endo_nbr
+    error('Shouldn''t arrive here')
+end
+
+av = M_.aux_vars([M_.aux_vars.endo_index] == auxVar);
+
+if av.type == 8 || av.type == 10
+    idx = av.endo_index;
+else
+    if av.orig_index <= M_.orig_endo_nbr
+        idx = av.orig_index;
+    else
+        idx = findVarNoLag(av.orig_index);
+    end
+end
+end
+
+
+
+function [lag, ndiffs] = findLagForVar(auxVar, lag, ndiffs, rhsVars)
+
+global M_
+
+if auxVar <= M_.orig_endo_nbr
+    assert(lag > 0)
+    return
+end
+
+av = M_.aux_vars([M_.aux_vars.endo_index] == auxVar);
+
+if av.type == 8
+    ndiffs = ndiffs + 1;
+end
+
+if ismember(av.endo_index, rhsVars)
+    if av.type == 8 || av.type == 9
+        lag = lag + abs(av.orig_lead_lag);
+    end
+elseif ismember(av.orig_index, rhsVars)
+    if av.orig_index <= M_.orig_endo_nbr
+        lag = lag + abs(av.orig_lead_lag);
+    else
+        [lag, ndiffs] = findLagForVar(av.orig_index, lag + max(1, abs(av.orig_lead_lag)), ndiffs, rhsVars);
+    end
+else
+    if av.type == 8
+        [lag, ndiffs] = findLagForVar(av.orig_index, lag, ndiffs, rhsVars);
+    else
+        [lag, ndiffs] = findLagForVar(av.orig_index, lag + max(1, abs(av.orig_lead_lag)), ndiffs, rhsVars);
+    end
+end
+assert(lag > 0)
+end
+
diff --git a/matlab/get_companion_matrix.m b/matlab/get_companion_matrix.m
new file mode 100644
index 0000000000000000000000000000000000000000..9589d6514ab1173b35dd8f31d5da232278378060
--- /dev/null
+++ b/matlab/get_companion_matrix.m
@@ -0,0 +1,154 @@
+function [A0, A0star, AR, B] = get_companion_matrix(auxiliary_model_name, auxiliary_model_type)
+
+% Gets the companion VAR representation of a PAC auxiliary model.
+% Depending on the nature of this auxiliary model the output is
+% saved in oo_.{var,trend_component}.(auxiliary_model_name).CompanionMatrix
+%
+% INPUTS
+% - auxiliary_model_name     [string]    the name of the auxiliary model
+% - auxiliary_model_type     [string]    the type of the auxiliary model
+%                                        ('var' or 'trend_component')
+%
+% OUTPUTS
+% - None
+
+% Copyright (C) 2018-2019 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/>.
+
+global oo_ M_
+
+if nargin < 2
+    if isfield(M_, 'var') && isfield(M_.var, auxiliary_model_name)
+        auxiliary_model_type = 'var';
+    elseif isfield(M_, 'trend_component') && isfield(M_.trend_component, auxiliary_model_name)
+        auxiliary_model_type = 'trend_component';
+    else
+        error('Unknown type of auxiliary model.')
+    end
+end
+
+if strcmp(auxiliary_model_type, 'var')
+    AR = feval([M_.fname '.var_ar'], auxiliary_model_name, M_.params);
+elseif strcmp(auxiliary_model_type, 'trend_component')
+    [AR, A0, A0star] = feval([M_.fname '.trend_component_ar_a0'], auxiliary_model_name, M_.params);
+else
+    error('Unknown type of auxiliary model.')
+end
+
+% Get the number of lags
+p = size(AR, 3);
+
+% Get the number of variables
+n = length(M_.(auxiliary_model_type).(auxiliary_model_name).lhs);
+
+switch auxiliary_model_type
+  case 'var'
+    oo_.var.(auxiliary_model_name).CompanionMatrix = zeros(n*p);
+    oo_.var.(auxiliary_model_name).CompanionMatrix(1:n,1:n) = AR(:,:,1);
+    for i = 2:p
+        oo_.var.(auxiliary_model_name).CompanionMatrix(1:n,(i-1)*n+(1:n)) = AR(:,:,i);
+        oo_.var.(auxiliary_model_name).CompanionMatrix((i-1)*n+(1:n),(i-2)*n+(1:n)) = eye(n);
+    end
+    M_.var.(auxiliary_model_name).list_of_variables_in_companion_var = M_.endo_names(M_.var.(auxiliary_model_name).lhs);
+    if nargout
+        A0 = [];
+        A0star = [];
+        B  = [];
+    end
+  case 'trend_component'
+    % Get number of trends.
+    q = sum(M_.trend_component.(auxiliary_model_name).targets);
+    % Get the number of equations with error correction.
+    m  = n - q;
+    % Get the indices of trend and EC equations in the auxiliary model.
+    target_eqnums_in_auxiliary_model = M_.trend_component.(auxiliary_model_name).target_eqn;
+    ecm_eqnums_in_auxiliary_model = find(~M_.trend_component.(auxiliary_model_name).targets);
+
+    % REMARK It is assumed that the non trend equations are the error correction
+    %        equations. We assume that the model can be cast in the following form:
+    %
+    %        Δ Xₜ₋₁ = A₀ (Xₜ₋₁ - C₀Zₜ₋₁) + Σᵢ₌₁ᵖ Aᵢ Δ Xₜ₋ᵢ + ϵₜ
+    %
+    %        Zₜ = Zₜ₋₁ + ηₜ
+    %
+    %        where Xₜ is a n×1 vector and Zₜ is an m×1 vector, A₀ is a
+    %        n×n matrix, C₀ a n×m matrix, and Aᵢ (i=1,…,p) are n×n
+    %        matrices. Matrix C₀ can be factorized as C₀ = (A₀)⁻¹×Λ,
+    %        where Λ is a n×m matrix.
+    %
+    %        We rewrite the model in levels (we integrate the first set
+    %        of equations) and rewrite the model as a VAR(1) model. Let
+    %        Yₜ = [Xₜ; Zₜ] be the vertical concatenation of vectors
+    %        Xₜ (variables with EC) and Zₜ (trends). We have
+    %
+    %        Yₜ = Σᵢ₌₁ᵖ⁺¹ Bᵢ Yₜ₋ᵢ + [εₜ; ηₜ]
+    %
+    %        with
+    %
+    %               B₁ = [I+A₀+A₁, -Λ; 0, I]
+    %
+    %               Bᵢ = [Aᵢ-Aᵢ₋₁, 0; 0, 0]   for i = 2,…, p
+    %        and
+    %               Bₚ₊₁ = -[Aₚ, 0; 0, 0]
+    %
+    %        where the dimensions of I and 0 matrices can easily be
+    %        deduced from the number of EC and trend equations.
+
+    % Check that the lhs of candidate ecm equations are at least first differences.
+    for i = 1:m
+        if ~get_difference_order(M_.trend_component.(auxiliary_model_name).lhs(ecm_eqnums_in_auxiliary_model(i)))
+            error([auxiliary_model_name ' is not a trend component model. The LHS variables should be in differences'])
+        end
+    end
+    % Get the EC matrix (the EC term is assumend to be in t-1).
+    %
+    % TODO: Check that the EC term is the difference between the
+    %       endogenous variable and the trend variable.
+    %
+    % Build B matrices (VAR in levels)
+    B = zeros(m+q, m+q, p+1);
+    B(ecm_eqnums_in_auxiliary_model, ecm_eqnums_in_auxiliary_model, 1) = eye(m) + A0 + AR(:,:,1);
+    B(ecm_eqnums_in_auxiliary_model, target_eqnums_in_auxiliary_model) = -A0star;
+    B(target_eqnums_in_auxiliary_model, target_eqnums_in_auxiliary_model) = eye(q);
+    for i = 2:p
+        B(ecm_eqnums_in_auxiliary_model,ecm_eqnums_in_auxiliary_model,i) = AR(:,:,i) - AR(:,:,i-1);
+    end
+    B(ecm_eqnums_in_auxiliary_model,ecm_eqnums_in_auxiliary_model,p+1) = -AR(:,:,p);
+    % Write Companion matrix
+    oo_.trend_component.(auxiliary_model_name).CompanionMatrix = zeros(size(B, 1)*size(B, 3));
+    for i = 1:p
+        oo_.trend_component.(auxiliary_model_name).CompanionMatrix(1:n, (i-1)*n+(1:n)) = B(:,:,i);
+        oo_.trend_component.(auxiliary_model_name).CompanionMatrix(i*n+(1:n),(i-1)*n+(1:n)) = eye(n);
+    end
+    oo_.trend_component.(auxiliary_model_name).CompanionMatrix(1:n, p*n+(1:n)) = B(:,:,p+1);
+    M_.trend_component.(auxiliary_model_name).list_of_variables_in_companion_var = M_.endo_names(M_.trend_component.(auxiliary_model_name).lhs);
+    variables_rewritten_in_levels = M_.trend_component.(auxiliary_model_name).list_of_variables_in_companion_var(ecm_eqnums_in_auxiliary_model);
+    for i=1:m
+        id = get_aux_variable_id(variables_rewritten_in_levels{i});
+        if id
+            auxinfo = M_.aux_vars(id);
+            if auxinfo.type==8
+                M_.trend_component.(auxiliary_model_name).list_of_variables_in_companion_var(ecm_eqnums_in_auxiliary_model(i)) = ...
+                    {M_.endo_names{auxinfo.orig_index}};
+            else
+                error('This is a bug. Please contact the Dynare Team.')
+            end
+        else
+            error('This is a bug. Please contact the Dynare Team.')
+        end
+    end
+end
\ No newline at end of file
diff --git a/matlab/get_companion_matrix_legacy.m b/matlab/get_companion_matrix_legacy.m
new file mode 100644
index 0000000000000000000000000000000000000000..a7d6345e73184f27a6ac7ed2e461325528ac167e
--- /dev/null
+++ b/matlab/get_companion_matrix_legacy.m
@@ -0,0 +1,152 @@
+function [A0, AR, B] = get_companion_matrix_legacy(auxiliary_model_name, auxiliary_model_type)
+
+% Gets the companion VAR representation of a PAC auxiliary model.
+% Depending on the nature of this auxiliary model the output is
+% saved in oo_.{var,trend_component}.(auxiliary_model_name).CompanionMatrix
+%
+% INPUTS
+% - auxiliary_model_name     [string]    the name of the auxiliary model
+% - auxiliary_model_type     [string]    the type of the auxiliary model
+%                                        ('var' or 'trend_component')
+%
+% OUTPUTS
+% - None
+
+% Copyright (C) 2018 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/>.
+
+global oo_ M_
+
+if nargin<2
+    if isfield(M_, 'var') && isfield(M_.var, auxiliary_model_name)
+        auxiliary_model_type = 'var';
+    elseif isfield(M_, 'trend_component') && isfield(M_.trend_component, auxiliary_model_name)
+        auxiliary_model_type = 'trend_component';
+    else
+        error('Unknown type of auxiliary model.')
+    end
+end
+
+if nargout
+    A0 = [];
+    AR = [];
+    B = [];
+end
+
+get_ar_ec_matrices(auxiliary_model_name, auxiliary_model_type);
+
+% Get the number of lags
+p = size(oo_.(auxiliary_model_type).(auxiliary_model_name).ar, 3);
+
+% Get the number of variables
+n = length(oo_.(auxiliary_model_type).(auxiliary_model_name).ar(:,:,1));
+
+switch auxiliary_model_type
+  case 'var'
+    oo_.var.(auxiliary_model_name).CompanionMatrix = zeros(n*p);
+    oo_.var.(auxiliary_model_name).CompanionMatrix(1:n,1:n) = oo_.var.(auxiliary_model_name).ar(:,:,1);
+    for i=2:p
+        oo_.var.(auxiliary_model_name).CompanionMatrix(1:n,(i-1)*n+(1:n)) = oo_.var.(auxiliary_model_name).ar(:,:,i);
+        oo_.var.(auxiliary_model_name).CompanionMatrix((i-1)*n+(1:n),(i-2)*n+(1:n)) = eye(n);
+    end
+    AR = oo_.var.(auxiliary_model_name).ar;
+    M_.var.(auxiliary_model_name).list_of_variables_in_companion_var = M_.endo_names(M_.var.(auxiliary_model_name).lhs);
+  case 'trend_component'
+    % Get number of trends.
+    q = sum(M_.trend_component.(auxiliary_model_name).targets);
+    % Get the number of equations with error correction.
+    m  = n-q;
+    % Get the indices of trend and EC equations in the auxiliary model.
+    target_eqnums_in_auxiliary_model = find(M_.trend_component.(auxiliary_model_name).targets);
+    ecm_eqnums_in_auxiliary_model = find(~M_.trend_component.(auxiliary_model_name).targets);
+    % REMARK It is assumed that the non trend equations are the error correction
+    %        equations. We assume that the model can be cast in the following form:
+    %
+    %        Δ Xₜ₋₁ = A₀ (Xₜ₋₁ - Zₜ₋₁) + Σᵢ₌₁ᵖ Aᵢ Δ Xₜ₋ᵢ + ϵₜ
+    %
+    %        Zₜ = Zₜ₋₁ + ηₜ
+    %
+    %        We first recast the equation into this representation, and
+    %        we rewrite the model in levels (we integrate the first set
+    %        of equations) to rewrite the model as a VAR(1) model. Let
+    %        Yₜ = [Xₜ; Zₜ] be the vertical concatenation of vectors
+    %        Xₜ (variables with EC) and Zₜ (trends). We have
+    %
+    %        Yₜ = Σᵢ₌₁ᵖ⁺¹ Bᵢ Yₜ₋ᵢ + [εₜ; ηₜ]
+    %
+    %        with
+    %
+    %               B₁ = [I+Λ+A₁, -Λ; 0, I]
+    %
+    %               Bᵢ = [Aᵢ-Aᵢ₋₁, 0; 0, 0]   for i = 2,…, p
+    %        and
+    %               Bₚ₊₁ = -[Aₚ, 0; 0, 0]
+    %
+    %        where the dimensions of I and 0 matrices can easily be
+    %        deduced from the number of EC and trend equations.
+    % Check that the lhs of candidate ecm equations are at least first differences.
+    for i=1:m
+        if ~get_difference_order(M_.trend_component.(auxiliary_model_name).lhs(ecm_eqnums_in_auxiliary_model(i)))
+            error('Model %s is not a Trend component  model! LHS variables should be in difference', auxiliary_model_name)
+        end
+    end
+    % Reorder target_eqnums_in_auxiliary_model to ensure that the order of
+    % the trend variables matches the order of the error correction
+    % variables.
+    [~,reorder] = ismember(M_.trend_component.(auxiliary_model_name).lhs(target_eqnums_in_auxiliary_model), ...
+                           M_.trend_component.(auxiliary_model_name).target_vars(find(M_.trend_component.(auxiliary_model_name).target_vars>0)));
+    target_eqnums_in_auxiliary_model = target_eqnums_in_auxiliary_model(reorder);
+    % Get the EC matrix (the EC term is assumend to be in t-1).
+    %
+    % TODO: Check that the EC term is the difference between the
+    %       endogenous variable and the trend variable.
+    %
+    A0 = oo_.trend_component.(auxiliary_model_name).ec(ecm_eqnums_in_auxiliary_model,:,1);
+    % Get the AR matrices.
+    AR = oo_.trend_component.(auxiliary_model_name).ar(ecm_eqnums_in_auxiliary_model,ecm_eqnums_in_auxiliary_model,:);
+    % Build B matrices (VAR in levels)
+    B(ecm_eqnums_in_auxiliary_model,ecm_eqnums_in_auxiliary_model,1) = eye(m)+A0+AR(:,:,1);
+    B(ecm_eqnums_in_auxiliary_model,target_eqnums_in_auxiliary_model) = -A0;
+    B(target_eqnums_in_auxiliary_model,target_eqnums_in_auxiliary_model) = eye(q);
+    for i=2:p
+        B(ecm_eqnums_in_auxiliary_model,ecm_eqnums_in_auxiliary_model,i) = AR(:,:,i)-AR(:,:,i-1);
+    end
+    B(ecm_eqnums_in_auxiliary_model,ecm_eqnums_in_auxiliary_model,p+1) = -AR(:,:,p);
+    % Write Companion matrix
+    oo_.trend_component.(auxiliary_model_name).CompanionMatrix = zeros(size(B, 1)*size(B, 3));
+    for i=1:p
+        oo_.trend_component.(auxiliary_model_name).CompanionMatrix(1:n, (i-1)*n+(1:n)) = B(:,:,i);
+        oo_.trend_component.(auxiliary_model_name).CompanionMatrix(i*n+(1:n),(i-1)*n+(1:n)) = eye(n);
+    end
+    oo_.trend_component.(auxiliary_model_name).CompanionMatrix(1:n, p*n+(1:n)) = B(:,:,p+1);
+    M_.trend_component.(auxiliary_model_name).list_of_variables_in_companion_var = M_.endo_names(M_.trend_component.(auxiliary_model_name).lhs);
+    variables_rewritten_in_levels = M_.trend_component.(auxiliary_model_name).list_of_variables_in_companion_var(ecm_eqnums_in_auxiliary_model);
+    for i=1:m
+        id = get_aux_variable_id(variables_rewritten_in_levels{i});
+        if id
+            auxinfo = M_.aux_vars(id);
+            if auxinfo.type==8
+                M_.trend_component.(auxiliary_model_name).list_of_variables_in_companion_var(ecm_eqnums_in_auxiliary_model(i)) = ...
+                    {M_.endo_names{auxinfo.orig_index}};
+            else
+                error('This is a bug. Please contact the Dynare Team.')
+            end
+        else
+            error('This is a bug. Please contact the Dynare Team.')
+        end
+    end
+end
\ No newline at end of file
diff --git a/matlab/get_equation_number_by_tag.m b/matlab/get_equation_number_by_tag.m
index 596a5c1b3f4a7c304528b8f580106f5a59a07f9c..fc7d097c4b610fcac1a58098e5d2e49a48401896 100644
--- a/matlab/get_equation_number_by_tag.m
+++ b/matlab/get_equation_number_by_tag.m
@@ -1,14 +1,15 @@
-function eqnumber = get_equation_number_by_tag(eqname)
+function eqnumber = get_equation_number_by_tag(eqname, DynareModel)
 
 % Translates an equation name into an equation number.
 %
 % INPUTS
-% - eqname   [string]    Name of the equation.
+% - eqname        [char]     1×n array, name of the equation.
+% - DynareModel   [struct]   Structure describing the model, aka M_.
 %
 % OUTPUTS
-% - eqnumber [integer]   Equation number.
+% - eqnumber      [integer]  Equation number.
 
-% Copyright (C) 2018 Dynare Team
+% Copyright © 2018-2020 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -25,8 +26,6 @@ function eqnumber = get_equation_number_by_tag(eqname)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
 
-global M_
-
-eqnumber = strmatch(eqname, M_.equations_tags(strmatch('name', M_.equations_tags(:,2), 'exact'), 3), 'exact');
+eqnumber = strmatch(eqname, DynareModel.equations_tags(strmatch('name', DynareModel.equations_tags(:,2), 'exact'), 3), 'exact');
 
 if isempty(eqnumber), eqnumber = 0; end
\ No newline at end of file
diff --git a/matlab/get_lhs_and_rhs.m b/matlab/get_lhs_and_rhs.m
index 15932a5a6a503d2fe2a3d5c8b779a62b68f6f4d6..0c93f3acae3c4327d9b0caad871709435b47b7b6 100644
--- a/matlab/get_lhs_and_rhs.m
+++ b/matlab/get_lhs_and_rhs.m
@@ -1,14 +1,18 @@
-function [lhs, rhs] = get_lhs_and_rhs(eqname, DynareModel, original)
+function [lhs, rhs, json] = get_lhs_and_rhs(eqname, DynareModel, original, json)
 
 % Returns the left and right handsides of an equation.
 %
 % INPUTS
-% - lhs         [string]            Left hand side of the equation.
-% - rhs         [string]            Right hand side of the equation.
-% - DynareModel [struct]            Structure describing the current model (M_).
+% - eqname       [char]            Name of the equation.
+% - DynareModel  [struct]          Structure describing the current model (M_).
+% - original     [logical]         fetch equation in modfile-original.json or modfile.json
+% - json         [char]            content of the JSON file
 %
 % OUTPUTS
-% - eqname      [string]            Name of the equation.
+% - lhs          [char]            Left hand side of the equation.
+% - rhs          [char]            Right hand side of the equation.
+
+%
 %
 % SPECIAL REQUIREMENTS
 %  The user must have attached names to the equations using equation
@@ -19,7 +23,7 @@ function [lhs, rhs] = get_lhs_and_rhs(eqname, DynareModel, original)
 %      [name='Phillips curve']
 %      pi = beta*pi(1) + slope*y + lam;
 
-% Copyright (C) 2018 Dynare Team
+% Copyright © 2018-2020 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -36,17 +40,26 @@ function [lhs, rhs] = get_lhs_and_rhs(eqname, DynareModel, original)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
 
-if nargin<3
+if nargin<3 || isempty(original)
     original = false;
 end
 
-% Get the equation from the JSON output.
-if original
-    jsonfil = loadjson([DynareModel.fname filesep() 'model' filesep() 'json' filesep() 'modfile-original.json']);
-else
-    jsonfil = loadjson([DynareModel.fname filesep() 'model' filesep() 'json' filesep() 'modfile.json']);
+% Load JSON file if nargin<4
+if nargin<4
+    if original
+        json = loadjson_([DynareModel.fname filesep() 'model' filesep() 'json' filesep() 'modfile-original.json']);
+    else
+        json = loadjson_([DynareModel.fname filesep() 'model' filesep() 'json' filesep() 'modfile.json']);
+    end
 end
-jsonmod = jsonfil.model;
+
+% Load model.
+jsonmod = json.model;
+if isstruct(jsonmod)
+    jsonmod = {jsonmod};
+end
+
+% Load equation.
 jsoneqn = getEquationsByTags(jsonmod, 'name', eqname);
 
 % Get the lhs and rhs members of the selected equation.
diff --git a/matlab/get_variables_and_parameters_in_equation.m b/matlab/get_variables_and_parameters_in_equation.m
index 58ab88e7880e10379b960c7a2ee9d9c7fb2cfc94..b4ed92a2c8630d5d16aee35643db64d1242e9b81 100644
--- a/matlab/get_variables_and_parameters_in_equation.m
+++ b/matlab/get_variables_and_parameters_in_equation.m
@@ -15,7 +15,7 @@ function [pnames, enames, xnames, pid, eid, xid] = get_variables_and_parameters_
 % - eid         [Integer]           n*1 vector of indices in M_.endo_names for the listed parameters in endogenous.
 % - xid         [Integer]           m*1 vector of indices in M_.exo_names for the listed parameters in exogenous.
 
-% Copyright (C) 2018-2019 Dynare Team
+% Copyright (C) 2018-2020 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -33,38 +33,22 @@ function [pnames, enames, xnames, pid, eid, xid] = get_variables_and_parameters_
 % along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
 
 % Get the tokens in the rhs member of the equation.
-rhs_ = strsplit(rhs,{'+','-','*','/','^', ...
-                    'log(', 'log10(', 'ln(', 'exp(', ...
-                    'sqrt(', 'abs(', 'sign(', ...
-                    'sin(', 'cos(', 'tan(', 'asin(', 'acos(', 'atan(', ...
-                    'min(', 'max(', ...
-                    'normcdf(', 'normpdf(', 'erf(', ...
-                    'diff(', 'adl(', '(', ')'});
+rhs_ = get_variables_and_parameters_in_expression(rhs);
 
-% Filter out the numbers and punctuation.
-rhs_(cellfun(@(x) all(isstrprop(x, 'digit')+isstrprop(x, 'punct')), rhs_)) = [];
+% Get the tokens in the lhs member of the equation.
+lhs_ = get_variables_and_parameters_in_expression(lhs);
 
 % Get list of parameters.
 pnames = DynareModel.param_names;
-pnames = intersect(rhs_, pnames);
+pnames = intersect([rhs_, lhs_], pnames);
 
 % Get list of endogenous variables.
 enames = DynareModel.endo_names;
-enames = intersect(rhs_, enames);
+enames = intersect([rhs_, lhs_], enames);
 
 % Get list of exogenous variables
 xnames = DynareModel.exo_names;
-xnames = intersect(rhs_, xnames);
-
-% Decide if we are dealing with a dynamic model. If so, the lhs variable
-% already belongs to enames, we remove this variable from enames.
-id = find(strcmp(lhs, enames));
-if ~isempty(id)
-    enames(id) = [];
-end
-
-% Add lhs variable in first position of enames.
-enames = [lhs; enames];
+xnames = intersect([rhs_,lhs_], xnames);
 
 % Returns vector of indices for parameters endogenous and exogenous
 % variables if required.
@@ -84,4 +68,4 @@ if nargout>3
     for i = 1:p
         xid(i) = find(strcmp(xnames{i}, DynareModel.exo_names));
     end
-end
\ No newline at end of file
+end
diff --git a/matlab/get_variables_and_parameters_in_expression.m b/matlab/get_variables_and_parameters_in_expression.m
new file mode 100644
index 0000000000000000000000000000000000000000..1af17ebbc95b41fbd4dafecaf5174dfcc8d6717e
--- /dev/null
+++ b/matlab/get_variables_and_parameters_in_expression.m
@@ -0,0 +1,40 @@
+function objects = get_variables_and_parameters_in_expression(expr)
+
+% Returns the variables and parameters appearing in an expression.
+%
+% INPUTS
+% - expr       [char]             1×m char array, dynare model expression (typically RHS or LHS of an equation).
+%
+% OUTPUTS
+% - objects    [cell]             cell of row char arrays, names of the variables and parameters in expr.
+
+% Copyright (C) 2020 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/>.
+
+objects = strsplit(expr, {'+','-','*','/','^', ...
+                    'log(', 'log10(', 'ln(', 'exp(', ...
+                    'sqrt(', 'abs(', 'sign(', ...
+                    'sin(', 'cos(', 'tan(', 'asin(', 'acos(', 'atan(', ...
+                    'min(', 'max(', ...
+                    'normcdf(', 'normpdf(', 'erf(', ...
+                    'diff(', 'adl(', '(', ')', '\n', '\t', ' '});
+
+% Filter out the numbers, punctuation.
+objects(cellfun(@(x) all(isstrprop(x, 'digit')+isstrprop(x, 'punct')), objects)) = [];
+
+% Filter out empty elements.
+objects(cellfun(@(x) all(isempty(x)), objects)) = [];
\ No newline at end of file
diff --git a/matlab/global_initialization.m b/matlab/global_initialization.m
index fba7ec445e21c18a82b0618dd8d02a8a49d57a61..02220f79479d25b02dbc665b2d4f9f3706cfc2eb 100644
--- a/matlab/global_initialization.m
+++ b/matlab/global_initialization.m
@@ -156,3 +156,6 @@ if isfield(options_, 'global_init_file')
         error('Cannot find global initialization file (%s).', options_.global_init_file)
     end
 end
+
+end
+
diff --git a/matlab/hess_element.m b/matlab/hess_element.m
index 5af38ecd2a112d6f66d0f1b806c0e4b53bee9622..2c86e78c76dc11f3584081319448e661e8257843 100644
--- a/matlab/hess_element.m
+++ b/matlab/hess_element.m
@@ -1,15 +1,17 @@
-function d=hess_element(func,element1,element2,args)
-% function d=hess_element(func,element1,element2,args)
+function d=hess_element(func,arg1,arg2,elem1,elem2,args)
+% function d=hess_element(func,arg1,arg2,elem1,elem2,args)
 % returns an entry of the finite differences approximation to the hessian of func
 %
 % INPUTS
 %    func       [function name]    string with name of the function
-%    element1   [int]              the indices showing the element within the hessian that should be returned
-%    element2   [int]
+%    arg1       [int]              the indices showing the element within the hessian that should be returned
+%    arg2       [int]
+%    elem1      [int]              vector index 1
+%    elem2      [int]              vector index 2
 %    args       [cell array]       arguments provided to func
 %
 % OUTPUTS
-%    d          [double]           the (element1,element2) entry of the hessian
+%    d          [double]           the (arg1,arg2) entry of the hessian
 %
 % SPECIAL REQUIREMENTS
 %    none
@@ -31,7 +33,7 @@ function d=hess_element(func,element1,element2,args)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
 
-assert(element1 <= length(args) && element2 <= length(args));
+assert(arg1 <= length(args) && arg2 <= length(args));
 
 func = str2func(func);
 
@@ -43,21 +45,21 @@ m01 = args;
 p11 = args;
 m11 = args;
 
-p10{element1} = p10{element1} + h;
-m10{element1} = m10{element1} - h;
+p10{arg1}(elem1) = p10{arg1}(elem1) + h;
+m10{arg1}(elem1) = m10{arg1}(elem1) - h;
 
-p11{element1} = p11{element1} + h;
-m11{element1} = m11{element1} - h;
-        
-p01{element2} = p01{element2} + h;
-m01{element2} = m01{element2} - h;
+p11{arg1}(elem1) = p11{arg1}(elem1) + h;
+m11{arg1}(elem1) = m11{arg1}(elem1) - h;
 
-p11{element2} = p11{element2} + h;
-m11{element2} = m11{element2} - h;
+p01{arg2}(elem2) = p01{arg2}(elem2) + h;
+m01{arg2}(elem2) = m01{arg2}(elem2) - h;
+
+p11{arg2}(elem2) = p11{arg2}(elem2) + h;
+m11{arg2}(elem2) = m11{arg2}(elem2) - h;
 
 % From Abramowitz and Stegun. Handbook of Mathematical Functions (1965)
 % formulas 25.3.24 and 25.3.27 p. 884
-if element1==element2
+if arg1 == arg2 && elem1 == elem2
     d = (16*func(p10{:})...
          +16*func(m10{:})...
          -30*func(args{:})...
diff --git a/matlab/initvalf.m b/matlab/initvalf.m
index 17a5ff54a44de80b902bd3e58afb63ed29e73d6e..c6c9449c00e5571905aa125f1a4f69a507045774 100644
--- a/matlab/initvalf.m
+++ b/matlab/initvalf.m
@@ -29,6 +29,4 @@ function series = initvalf(M, options)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
 
-series = histvalf_initvalf('INITVALF', M, options);
-
-
+series = histvalf_initvalf('INITVALF', M, options);
\ No newline at end of file
diff --git a/matlab/isauxiliary.m b/matlab/isauxiliary.m
index a0032114f064de351913d2f69dbd787f97d607d4..da57d5ed0575a78618ae356e2f7c6523c448883a 100644
--- a/matlab/isauxiliary.m
+++ b/matlab/isauxiliary.m
@@ -1,10 +1,10 @@
-function b = isauxiliary(var, type)
+function b = isauxiliary(var, types)
 
 % Returns true if var is an auxiliary variable.
 %
 % INPUTS
 % - var       [string]    Name of the variable.
-% - type      [integer]   Type of auxiliary variable.
+% - types      [integer]  vector of type of auxiliary variables.
 %
 % OUTPUTS
 % - b         [logical]
@@ -64,6 +64,6 @@ end
 
 auxinfo = M_.aux_vars(get_aux_variable_id(id));
 
-if ~isequal(auxinfo.type, type)
+if ~ismember(auxinfo.type, types)
     b = false;
 end
\ No newline at end of file
diff --git a/matlab/iszero.m b/matlab/iszero.m
new file mode 100644
index 0000000000000000000000000000000000000000..b8efdd0e0eb4a01c8114f26486e2386d24270e39
--- /dev/null
+++ b/matlab/iszero.m
@@ -0,0 +1,22 @@
+function b = iszero(A)
+
+% Returns true iff all the elements of array A are 0.    
+
+% Copyright (C) 2018 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/>.
+
+b = all(~A(:));
\ No newline at end of file
diff --git a/matlab/jacob_element.m b/matlab/jacob_element.m
index 4f49cdbab917e1b291092770612e36f2e7368ed9..e2a04b426bea0a13676bf62bc6a7e6f928d2c64f 100644
--- a/matlab/jacob_element.m
+++ b/matlab/jacob_element.m
@@ -1,14 +1,15 @@
-function d=jacob_element(func,element,args)
-% function d=jacob_element(func,element,args)
+function d=jacob_element(func,arg,elem,args)
+% function d=jacob_element(func,arg,elem,args)
 % returns an entry of the finite differences approximation to the jacobian of func
 %
 % INPUTS
 %    func       [function name]    string with name of the function
-%    element    [int]              the index showing the element within the jacobian that should be returned
+%    arg        [int]              the index showing the elem within the jacobian that should be returned
+%    elem       [int]              vector index
 %    args       [cell array]       arguments provided to func
 %
 % OUTPUTS
-%    d          [double]           jacobian[element]
+%    d          [double]           jacobian[elem]
 %
 % SPECIAL REQUIREMENTS
 %    none
@@ -30,15 +31,15 @@ function d=jacob_element(func,element,args)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
 
-assert(element <= length(args));
+assert(arg <= length(args));
 
 func = str2func(func);
 
 h=1e-6;
 margs=args;
 
-args{element} = args{element} + h;
-margs{element} = margs{element} - h;
+args{arg}(elem) = args{arg}(elem) + h;
+margs{arg}(elem) = margs{arg}(elem) - h;
 
 d=(func(args{:})-func(margs{:}))/(2*h);
 end
diff --git a/matlab/loadjson_.m b/matlab/loadjson_.m
new file mode 100644
index 0000000000000000000000000000000000000000..7daeffd49a2cffbfe7e790ef7d0435c60d978a70
--- /dev/null
+++ b/matlab/loadjson_.m
@@ -0,0 +1,46 @@
+function o = loadjson_(jsonfilename)
+
+% Reads a json file using jsonlab toolbox or jsondecode builtin if available.
+%
+% INPUTS
+% - jsonfilename   [char]      1×n char array, name of the JSON file.
+%
+% OUTPUTS
+% - o              [struct]    content of the JSON file.
+%
+% REMARKS
+% jsondecode builtin was introduced in Matlab R2016b and is not
+% available under Octave. Old Matlab versions and Octave use
+% jsonlab as fallback. 
+
+% Copyright (C) 2020 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/>.
+
+if isoctave() || matlab_ver_less_than('9.1')
+    o = loadjson(jsonfilename);
+    return
+end
+
+json = fileread(jsonfilename);
+
+% Remove some escape characters that cannot be interpreted by jsondecode
+json = strrep(json, '\w', '\\w');
+json = strrep(json, '\_', '\\_');
+json = strrep(json, '\\\_', '\\_');
+
+o = jsondecode(json); clear('json');
+o = convertjsondecode(o);
\ No newline at end of file
diff --git a/matlab/ols/common_parsing.m b/matlab/ols/common_parsing.m
new file mode 100644
index 0000000000000000000000000000000000000000..0ebc4a2605724a91329b4a7510fdaf677bc40d8b
--- /dev/null
+++ b/matlab/ols/common_parsing.m
@@ -0,0 +1,127 @@
+function [Y, lhssub, X, startdates, enddates, residnames] = common_parsing(ds, ast, overlapping_dates, param_names)
+%function [Y, lhssub, X, startdates, enddates, residnames] = common_parsing(ds, ast, overlapping_dates, param_names)
+%
+% Code common to sur.m and pooled_ols.m
+%
+% INPUTS
+%   ds                [dseries]         dataset
+%   ast               [cell array]      JSON representation of abstract syntax tree
+%   overlapping_dates [boolean]         if true, dates are same across equations
+%
+% OUTPUTS
+%   Y                 [cell array]      dependent variables
+%   lhssub            [cell array]      RHS subtracted from LHS
+%   X                 [cell array]      regressors
+%   startdates        [cell array]      first observed period for each
+%                                       equation
+%   enddates          [cell array]      last observed period for each
+%                                       equation
+%   startidxs         [vector]          rows corresponding to each
+%                                       equation's observations
+%   residnames        [cell array]      name of residual in each equation
+%   param_names       [cellstr or cell] list of parameters to estimate (if
+%                                       empty, estimate all)
+%
+% SPECIAL REQUIREMENTS
+%   none
+
+% Copyright (C) 2019 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/>.
+
+global M_
+
+%% Initialize variables
+neqs = length(ast);
+Y = cell(neqs, 1);
+lhssub = cell(neqs, 1);
+X = cell(neqs, 1);
+startdates = cell(neqs, 1);
+enddates = cell(neqs, 1);
+residnames = cell(neqs, 1);
+
+%% Loop over equations
+for i = 1:neqs
+    [Y{i}, lhssub{i}, X{i}, residnames{i}, startdates{i}, enddates{i}] = ...
+        parse_ols_style_equation(ds, ast{i});
+end
+
+if overlapping_dates
+    maxfp = max([startdates{:}]);
+    minlp = min([enddates{:}]);
+    for i = 1:neqs
+        Y{i} = Y{i}(maxfp:minlp);
+        if ~isempty(X{i})
+            X{i} = X{i}(maxfp:minlp);
+        end
+        if ~isempty(lhssub{i})
+            lhssub{i} = lhssub{i}(maxfp:minlp);
+        end
+        startdates{i} = maxfp;
+        enddates{i} = minlp;
+    end
+end
+
+if ~isempty(param_names)
+    if iscell(param_names) && ~iscellstr(param_names)
+        assert(length(param_names) == neqs, 'error w param_names arg');
+    else
+        pn = param_names;
+        pn_found_cellstr = false(length(param_names), 1);
+    end
+    for i = 1:neqs
+        if iscell(param_names) && ~iscellstr(param_names)
+            pn = param_names{i};
+            pn_found_cellstr_i = false(length(pn), 1);
+        end
+        names = X{i}.name;
+        newlhssub = dseries();
+        for j = 1:length(names)
+            idx = find(strcmp(names{j}, pn));
+            if isempty(idx)
+                pval = M_.params(strcmp(names{j}, M_.param_names));
+                if isnan(pval) || isinf(pval)
+                    error(['Could not find param init value for ' names{j}])
+                end
+                newlhssub = newlhssub + pval * X{i}.(names{j});
+                X{i} = X{i}.remove(names{j});
+            else
+                if iscell(param_names) && ~iscellstr(param_names)
+                    pn_found_cellstr_i = true;
+                else
+                    pn_found_cellstr(idx) = true;
+                end
+            end
+        end
+        Y{i} = Y{i} - newlhssub;
+        lhssub{i} = lhssub{i} + newlhssub;
+        if iscell(param_names) && ~iscellstr(param_names)
+            if ~all(pn_found_cellstr_i)
+                error(['parameters specified in param_names (' ...
+                    strjoin(pn(~pn_found_cellstr_i), ', ') ...
+                    ') were not found in eq ' num2str(i) ' to be estimated'])
+            end
+        end
+    end
+    if ~(iscell(param_names) && ~iscellstr(param_names))
+        if ~all(pn_found_cellstr)
+            error(['parameters specified in param_names (' ...
+                strjoin(pn(~pn_found_cellstr), ', ') ...
+                ') were not found in the equation(s) to be estimated'])
+        end
+    end
+end
+end
diff --git a/matlab/ols/create_sur_report.m b/matlab/ols/create_sur_report.m
new file mode 100644
index 0000000000000000000000000000000000000000..86152866b16e177b6fdd53938e3a7b985962e0db
--- /dev/null
+++ b/matlab/ols/create_sur_report.m
@@ -0,0 +1,80 @@
+function create_sur_report()
+%function create_sur_report()
+% Creates report for all SUR models estimated in oo_
+%
+% INPUTS
+% none
+%
+% OUTPUTS
+% none
+%
+% SPECIAL REQUIREMENTS
+%   dynare must have been run with the option: json=compute
+
+% Copyright (C) 2019 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/>.
+
+global oo_
+
+if ~isfield(oo_, 'sur')
+    disp(['create_sur_report: to use this function you must '...
+        'have already estimated a SUR model']);
+    return
+end
+
+%% Begin Report
+rep = report();
+
+%% loop through SUR estimationsd
+fields = fieldnames(oo_.sur);
+for i = 1:length(fields)
+    rep = rep.addPage(...
+        'title', ['SUR model ' regexprep(fields{i}, '_', '\\_')], ...
+        'titleFormat', '\large\bfseries');
+
+    rep = rep.addSection('cols', 1);
+    preamble = sprintf('No. Equations: %d\\newline Observations: %d\\newline', ...
+        oo_.sur.(fields{i}).neqs, oo_.sur.(fields{i}).dof);
+    rep = rep.addParagraph(...
+        'indent', false, ...
+        'text', preamble);
+
+    rep = rep.addSection('cols', 1);
+    column_names = {'', 'Estimates','t-statistic','Std. Error'};
+    rep = rep.addTable(...
+        'precision', 5, ...
+        'column_names', column_names);
+    rep = rep.addData('data', {...
+        oo_.sur.(fields{i}).pname, ...
+        oo_.sur.(fields{i}).beta ...
+        oo_.sur.(fields{i}).tstat ...
+        oo_.sur.(fields{i}).stderr});
+    
+    rep = rep.addSection('cols', 1);
+    afterward = [sprintf('$R^2$: %f\\newline ', oo_.sur.(fields{i}).R2), ...
+        sprintf('$R^2$ Adjusted: %f\\newline ', oo_.sur.(fields{i}).adjR2), ...
+        sprintf('$s^2$: %f\\newline ', oo_.sur.(fields{i}).s2), ...
+        sprintf('Durbin-Watson: %f\\newline ', oo_.sur.(fields{i}).dw)];
+    rep = rep.addParagraph(...
+        'indent', false, ...
+        'text', afterward);
+end
+
+%% Write & Compile Report
+rep.write();
+rep.compile();
+end
diff --git a/matlab/ols/dyn_ols.m b/matlab/ols/dyn_ols.m
new file mode 100644
index 0000000000000000000000000000000000000000..dcb29aa02dfe6792780f97be3797cea383cee6bd
--- /dev/null
+++ b/matlab/ols/dyn_ols.m
@@ -0,0 +1,236 @@
+function ds = dyn_ols(ds, fitted_names_dict, eqtags, model_name, param_names, ds_range, update_params)
+% function varargout = dyn_ols(ds, fitted_names_dict, eqtags, model_name, param_names, ds_range)
+% Run OLS on chosen model equations; unlike olseqs, allow for time t
+% endogenous variables on LHS
+%
+% INPUTS
+%   ds                [dseries]         data
+%   fitted_names_dict [cell]            Nx2 or Nx3 cell array to be used in naming fitted
+%                                       values; first column is the equation tag,
+%                                       second column is the name of the
+%                                       associated fitted value, third column
+%                                       (if it exists) is the function name of
+%                                       the transformation to perform on the
+%                                       fitted value.
+%   eqtags            [cellstr]         names of equation tags to estimate. If empty,
+%                                       estimate all equations
+%   model_name        [celltsr]         name to use in oo_ and inc file (must be
+%                                       same size as eqtags)
+%   param_names       [cell of cellstr] list of parameters to estimate by eqtag
+%                                       (if empty, estimate all)
+%   ds_range          [dates]           range of dates to use in estimation
+%   update_params     [logical]         If false M_.params will not be estimation.
+%                                       If true (default) M_.params will be updated.
+%
+% OUTPUTS
+%   ds                [dseries]    data updated with fitted values
+%
+% SPECIAL REQUIREMENTS
+%   dynare must have been run with the option: json=compute
+
+% Copyright (C) 2017-2020 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/>.
+
+global M_ oo_ options_
+
+if nargin < 1 || nargin > 7
+    error('dyn_ols() takes between 1 and 7 arguments')
+end
+
+if isempty(ds) || ~isdseries(ds)
+    error('dyn_ols: the first argument must be a dseries')
+end
+
+if nargin == 6 && ~isempty(ds_range)
+    update_params = true;
+elseif nargin < 6
+    ds_range = ds.dates;
+    update_params = true;
+else
+    if isempty(ds_range)
+        ds_range = ds.dates;
+    else
+        if ds_range(1) < ds.firstdate || ds_range(end) > lastdate(ds)
+            error('There is a problem with the 6th argument: the date range does not correspond to that of the dseries')
+        end
+    end
+    update_params = true;
+end
+
+if nargin < 5
+    param_names = {};
+else
+    if ~isempty(param_names)
+        if ~iscell(param_names) || (~isempty(eqtags) && length(param_names) ~= length(eqtags))
+            error('The 5th argument, if provided, must be a cell of the same length as the eqtags argument')
+        end
+        for i = 1:length(param_names)
+            if ~iscellstr(param_names{i})
+                error('every entry of param_names must be a cellstr')
+            end
+        end
+    end
+end
+
+if nargin < 3
+    eqtags = {};
+end
+
+if nargin < 2
+    fitted_names_dict = {};
+else
+    assert(isempty(fitted_names_dict) || ...
+        (iscell(fitted_names_dict) && ...
+        (size(fitted_names_dict, 2) == 2 || size(fitted_names_dict, 2) == 3)), ...
+        'dyn_ols: the second argument must be an Nx2 or Nx3 cell array');
+end
+
+%% Get Equation(s)
+ast = get_ast(eqtags);
+
+%% Set model_name
+if nargin < 4
+    model_name = cell(length(ast), 1);
+else
+    if isempty(model_name)
+        model_name = repmat({''}, length(ast), 1);
+    else
+        if ~iscellstr(model_name) || length(model_name) ~= length(ast)
+            error('The length of the 4th argument must be a cellstr with length equal to the number of equations estimated')
+        end
+        for i = 1:length(model_name)
+            if ~isvarname(model_name{i})
+                error('Every entry in the 4th argument must be a valid string');
+            end
+        end
+    end
+end
+
+%% Parse equations
+[Y, lhssub, X, fp, lp] = common_parsing(ds(ds_range), ast, true, param_names);
+
+%% Loop over equations
+for i = 1:length(Y)
+    pnames = X{i}.name;
+    [nobs, nvars] = size(X{i}.data);
+
+    if ~isempty(model_name{i})
+        tag = model_name{i};
+    else
+        if isfield(ast{i}, 'tags') && isfield(ast{i}.tags, 'name')
+            tag = ast{i}.tags.('name');
+        else
+            tag = ['eq_line_no_' num2str(ast{i}.line)];
+        end
+    end
+
+    %% Estimation
+    % From LeSage, James P. "Applied Econometrics using MATLAB"
+    oo_.ols.(tag).dof = nobs - nvars;
+
+    % Estimated Parameters
+    [q, r] = qr(X{i}.data, 0);
+    xpxi = (r'*r)\eye(nvars);
+    oo_.ols.(tag).beta = r\(q'*Y{i}.data);
+    oo_.ols.(tag).param_idxs = zeros(length(pnames), 1);
+    for j = 1:length(pnames)
+        if ~strcmp(pnames{j}, 'intercept')
+            oo_.ols.(tag).param_idxs(j) = find(strcmp(M_.param_names, pnames{j}));
+            if update_params
+                M_.params(oo_.ols.(tag).param_idxs(j)) = oo_.ols.(tag).beta(j);
+            end
+        end
+    end
+
+    % Write .inc file
+    write_param_init_inc_file('ols', tag, oo_.ols.(tag).param_idxs, oo_.ols.(tag).beta);
+
+    % Yhat
+    idx = 0;
+    yhatname = [tag '_FIT'];
+    if ~isempty(fitted_names_dict)
+        idx = strcmp(fitted_names_dict(:,1), tag);
+        if any(idx)
+            yhatname = fitted_names_dict{idx, 2};
+        end
+    end
+    oo_.ols.(tag).Yhat = dseries(X{i}.data*oo_.ols.(tag).beta, fp{i}, yhatname);
+
+    % Residuals
+    oo_.ols.(tag).resid = Y{i} - oo_.ols.(tag).Yhat;
+
+    % Correct Yhat reported back to user
+    Y{i} = Y{i} + lhssub{i};
+    oo_.ols.(tag).Yobs = Y{i};
+    oo_.ols.(tag).Yhat = oo_.ols.(tag).Yhat + lhssub{i};
+    oo_.ols.(tag).YhatOrig = oo_.ols.(tag).Yhat;
+
+    % Apply correcting function for Yhat if it was passed
+    if any(idx) ...
+            && length(fitted_names_dict(idx, :)) == 3 ...
+            && ~isempty(fitted_names_dict{idx, 3})
+        oo_.ols.(tag).Yhat = ...
+            feval(fitted_names_dict{idx, 3}, oo_.ols.(tag).Yhat);
+    end
+    ds.(oo_.ols.(tag).Yhat.name) = oo_.ols.(tag).Yhat;
+
+    %% Calculate statistics
+    % Estimate for sigma^2
+    SS_res = oo_.ols.(tag).resid.data'*oo_.ols.(tag).resid.data;
+    oo_.ols.(tag).s2 = SS_res/oo_.ols.(tag).dof;
+
+    % R^2
+    ym = Y{i}.data - mean(Y{i});
+    SS_tot = ym'*ym;
+    oo_.ols.(tag).R2 = 1 - SS_res/SS_tot;
+
+    % Adjusted R^2
+    oo_.ols.(tag).adjR2 = oo_.ols.(tag).R2 - (1 - oo_.ols.(tag).R2)*(nvars-1)/(oo_.ols.(tag).dof);
+
+    % Durbin-Watson
+    ediff = oo_.ols.(tag).resid.data(2:nobs) - oo_.ols.(tag).resid.data(1:nobs-1);
+    oo_.ols.(tag).dw = (ediff'*ediff)/SS_res;
+
+    % Standard Error
+    oo_.ols.(tag).stderr = sqrt(oo_.ols.(tag).s2*diag(xpxi));
+
+    % T-Stat
+    oo_.ols.(tag).tstat = oo_.ols.(tag).beta./oo_.ols.(tag).stderr;
+
+    %% Print Output
+    if ~options_.noprint
+        if nargin == 3
+            title = ['OLS Estimation of equation ''' tag ''' [name = ''' tag ''']'];
+        else
+            title = ['OLS Estimation of equation ''' tag ''''];
+        end
+
+        preamble = {['Dependent Variable: ' Y{i}.name{:}], ...
+            sprintf('No. Independent Variables: %d', nvars), ...
+            sprintf('Observations: %d from %s to %s\n', nobs, fp{i}.char, lp{i}.char)};
+
+        afterward = {sprintf('R^2: %f', oo_.ols.(tag).R2), ...
+            sprintf('R^2 Adjusted: %f', oo_.ols.(tag).adjR2), ...
+            sprintf('s^2: %f', oo_.ols.(tag).s2), ...
+            sprintf('Durbin-Watson: %f', oo_.ols.(tag).dw)};
+
+        dyn_table(title, preamble, afterward, pnames, ...
+            {'Estimates','t-statistic','Std. Error'}, 4, ...
+            [oo_.ols.(tag).beta oo_.ols.(tag).tstat oo_.ols.(tag).stderr]);
+    end
+end
+end
\ No newline at end of file
diff --git a/matlab/ols/getEquationsByTags.m b/matlab/ols/getEquationsByTags.m
new file mode 100644
index 0000000000000000000000000000000000000000..29edee83253508a5dde3fb30b6e97d63478a9fd3
--- /dev/null
+++ b/matlab/ols/getEquationsByTags.m
@@ -0,0 +1,76 @@
+function [ast] = getEquationsByTags(ast, tagname, tagvalue)
+%function [ast] = getEquationsByTags(ast, tagname, tagvalue)
+% Return the ast structure with the matching tags
+%
+% INPUTS
+%   ast       [cell array]    JSON representation of model block
+%   tagname   [string]        The name of the tag whos values are to
+%                             be selected
+%   tagvalue  [string]        The values to be selected for the
+%                             provided tagname
+%
+% OUTPUTS
+%   ast       [cell array]    JSON representation of model block,
+%                             with equations removed that don't match
+%                             eqtags
+%
+% SPECIAL REQUIREMENTS
+%   none
+
+% Copyright (C) 2017-2019 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/>.
+
+if nargin ~= 3
+    error('Incorrect number of arguments passed to function')
+end
+
+if isempty(ast) || ~iscell(ast)
+    error('the first argument must be a cell array of structs');
+end
+
+if ~ischar(tagname)
+    error('Tag name must be a string');
+end
+
+if ~ischar(tagvalue) && ~iscell(tagvalue)
+    error('Tag value must be a string or a cell string array');
+end
+
+if ischar(tagvalue)
+    tagvalue = {tagvalue};
+end
+
+idx2keep = [];
+for i = 1:length(tagvalue)
+    found = false;
+    for j=1:length(ast)
+        assert(isstruct(ast{j}), 'Every entry in the ast must be a struct');
+        if isfield(ast{j}, 'tags') && ...
+                isfield(ast{j}.tags, tagname) && ...
+                strcmp(ast{j}.tags.(tagname), tagvalue{i})
+            idx2keep = [idx2keep; j];
+            found = true;
+            break
+        end
+    end
+    if found == false
+        warning(['getEquationsByTags: no equation tag found by the name of ''' tagvalue{i} ''''])
+    end
+end
+assert(~isempty(idx2keep), 'getEquationsByTags: no equations selected');
+ast = ast(unique(idx2keep, 'stable'));
+end
diff --git a/matlab/ols/get_ast.m b/matlab/ols/get_ast.m
new file mode 100644
index 0000000000000000000000000000000000000000..833bef4d8ef502b3c1a49d0ad3e70c443ccbfc3e
--- /dev/null
+++ b/matlab/ols/get_ast.m
@@ -0,0 +1,58 @@
+function [ast, jsonmodel] = get_ast(eqtags)
+
+% Returns the Abstract Syntax Tree the JSON output of preprocessor for the
+% given equation tags. Equations are ordered in eqtag order
+%
+% INPUTS
+% - eqtags     [cellstr]    names of equation tags for which to get info.
+%                           If empty, get all equations
+%
+% OUTPUTS
+% - ast        [cell array]  JSON representation of the abstract syntax tree
+% - jsonmodel  [cell array]  JSON representation of the equations.
+%
+% SPECIAL REQUIREMENTS
+%   none
+
+% Copyright (C) 2019 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/>.
+
+global M_
+
+if ~isempty(eqtags) && ~(ischar(eqtags) || iscell(eqtags))
+    error('eqtags not passed correctly')
+end
+
+jsonfile = sprintf('%s%smodel%sjson%smodfile-original.json', M_.fname, filesep(), filesep(), filesep());
+
+if ~exist(jsonfile, 'file')
+    error('Could not find %s! Please use the json=compute option (see the Dynare invocation section in the reference manual).', jsonfile)
+end
+
+tmp = loadjson_(jsonfile);
+ast = tmp.abstract_syntax_tree;
+
+if nargout>1
+    jsonmodel = tmp.model;
+end
+
+if ~isempty(eqtags)
+    ast = getEquationsByTags(ast, 'name', eqtags);
+    if nargout>1
+        jsonmodel = getEquationsByTags(jsonmodel, 'name', eqtags);
+    end
+end
\ No newline at end of file
diff --git a/matlab/ols/handle_constant_eqs.m b/matlab/ols/handle_constant_eqs.m
new file mode 100644
index 0000000000000000000000000000000000000000..bd69679e4d74194cfd6e59c71c8fb38bbb583caa
--- /dev/null
+++ b/matlab/ols/handle_constant_eqs.m
@@ -0,0 +1,50 @@
+function ast = handle_constant_eqs(ast)
+%function ast = handle_constant_eqs(ast)
+%
+% Code to handle equations of type `X = 0;` in AST. Returns equation(s)
+% removed from AST.
+%
+% INPUTS
+%   ast       [cell array]  JSON representation of abstract syntax tree
+%
+% OUTPUTS
+%   ast       [cell array]  updated JSON representation of abstract syntax tree
+%
+% SPECIAL REQUIREMENTS
+%   none
+
+% Copyright (C) 2019 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/>.
+
+if nargin ~= 1
+    error('Incorrect number of arguments to function')
+end
+
+if isempty(ast) || ~iscell(ast)
+    error('ast must be a cell')
+end
+
+for i = length(ast):-1:1
+    assert(strcmp(ast{i}.AST.node_type, 'BinaryOpNode') && strcmp(ast{i}.AST.op, '='), 'Expecting equation');
+    if strcmp(ast{i}.AST.arg2.node_type, 'NumConstNode')
+        if ~strcmp(ast{i}.AST.arg1.node_type, 'VariableNode')
+            error('At the moment only handling Variable Nodes on LHS')
+        end
+        ast = ast([1:i-1, i+1:end]);
+    end
+end
+end
diff --git a/matlab/ols/parse_ols_style_equation.m b/matlab/ols/parse_ols_style_equation.m
new file mode 100644
index 0000000000000000000000000000000000000000..bbe063ec9dd925a47fb76a5bf74f3d6d85d16d37
--- /dev/null
+++ b/matlab/ols/parse_ols_style_equation.m
@@ -0,0 +1,404 @@
+function [Y, lhssub, X, residual, fp, lp] = parse_ols_style_equation(ds, ast)
+%function [Y, lhssub, X, residual, fp, lp] = parse_ols_style_equation(ds, ast)
+% Run OLS on chosen model equations; unlike olseqs, allow for time t
+% endogenous variables on LHS
+%
+% INPUTS
+%   ds          [dseries]     data
+%   ast         [struct]      AST representing the equation to be parsed
+%
+% OUTPUTS
+%   Y           [dseries]     LHS of the equation (with lhssub subtracted)
+%   lhssub      [dseries]     RHS subtracted from LHS
+%   X           [dseries]     RHS of the equation
+%   residual    [string]      name of residual in equation
+%   fp          [date]        first common observed period between Y, lhssub, and X
+%   lp          [date]        last common observed period between Y, lhssub, and X
+%
+% SPECIAL REQUIREMENTS
+%   none
+
+% Copyright (C) 2019 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/>.
+
+%% Check inputs
+if nargin ~= 2
+    error('parse_ols_style_equation takes 2 arguments')
+end
+
+if isempty(ds) || ~isdseries(ds)
+    error('parse_ols_style_equation: arg 1 must be a dseries');
+end
+
+if isempty(ast) || ~isstruct(ast)
+    error('parse_ols_style_equation: arg 2 must be a struct');
+end
+
+line = ast.line;
+if ~strcmp(ast.AST.node_type, 'BinaryOpNode') ...
+        || ~strcmp(ast.AST.op, '=')
+    parsing_error('expecting equation with equal sign', line);
+end
+
+% Check LHS
+if ~strcmp(ast.AST.arg1.node_type, 'VariableNode') ...
+        && ~strcmp(ast.AST.arg1.node_type, 'UnaryOpNode')
+    parsing_error('expecting Variable or UnaryOp on LHS', line);
+else
+    if ~isOlsVar(ds, ast.AST.arg1) || ~isBaseVarLagEqualToZero(ast.AST.arg1)
+        parsing_error('the LHS of the equation must be an Variable or UnaryOp with lag == 0 that exists in the dataset', line);
+    end
+end
+
+%% Set LHS (Y)
+lhssub = dseries();
+Y = evalNode(ds, ast.AST.arg1, line, dseries());
+
+%% Set RHS (X)
+residual = '';
+X = dseries();
+terms = decomposeAdditiveTerms([], ast.AST.arg2, 1);
+for i = 1:length(terms)
+    Xtmp = dseries();
+    node_sign = terms{i}{2};
+    node_to_parse = terms{i}{1};
+    if strcmp(node_to_parse.node_type, 'VariableNode')
+        if strcmp(node_to_parse.type, 'parameter')
+            % Intercept
+            Xtmp = dseries(1, ds.dates, node_to_parse.name)*node_sign;
+        elseif strcmp(node_to_parse.type, 'exogenous') && ~any(strcmp(ds.name, node_to_parse.name))
+            % Residual if not contained in ds
+            if isempty(residual)
+                residual = node_to_parse.name;
+            else
+                parsing_error(['only one residual allowed per equation; encountered ' residual ' & ' node_to_parse.name], line);
+            end
+        elseif strcmp(node_to_parse.type, 'endogenous') ...
+                || (strcmp(node_to_parse.type, 'exogenous') && any(strcmp(ds.name, node_to_parse.name)))
+            % Subtract VariableNode from LHS
+            % NB: treat exogenous that exist in ds as endogenous
+            lhssub = lhssub + evalNode(ds, node_to_parse, line, dseries())*node_sign;
+        else
+            parsing_error('unexpected variable type found', line, node_to_parse);
+        end
+    elseif strcmp(node_to_parse.node_type, 'UnaryOpNode')
+        % Subtract UnaryOpNode from LHS
+        % NB: treat exogenous that exist in ds as endogenous
+        lhssub = lhssub + evalNode(ds, node_to_parse, line, dseries());
+    elseif strcmp(node_to_parse.node_type, 'BinaryOpNode') && strcmp(node_to_parse.op, '/')
+        % Subtract Node from LHS
+        % if either arg contains a parameter, it's a parsing error.
+        if containsParameter(node_to_parse, line)
+            parsing_error('unexpected node found', line, node_to_parse)
+        end
+        lhssub = lhssub + evalNode(ds, node_to_parse, line, dseries());
+    elseif strcmp(node_to_parse.node_type, 'BinaryOpNode') && strcmp(node_to_parse.op, '*')
+        % Parse param_expr * endog_expr
+        [Xtmp, names] = parseTimesNode(ds, node_to_parse, line);
+        Xtmp = Xtmp*node_sign;
+        if Xtmp.vobs > 1 || ...
+                (Xtmp.vobs == 1 && ~isnan(str2double(Xtmp.name)))
+            % Handle constraits
+            % Look through Xtmp names for constant
+            % if found, subtract from LHS
+            for j = 1:length(names)
+                if strcmp(names{j}{1}.node_type, 'NumConstNode')
+                    pname = num2str(names{j}{1}.value);
+                elseif strcmp(names{j}{1}.node_type, 'VariableNode')
+                    pname = names{j}{1}.name;
+                else
+                    parsing_error('unexpected node type', node_to_parse, line);
+                end
+                psign = names{j}{2};
+                if ~isnan(str2double(pname))
+                    lhssub = lhssub + psign * str2double(pname) * Xtmp.(pname);
+                    Xtmp = Xtmp.remove(pname);
+                else
+                    % Multiply by psign now so that it can be added together below
+                    % Otherwise, it would matter which was encountered first,
+                    % a parameter on its own or a linear constraint
+                    Xtmp.(pname) = psign * Xtmp.(pname);
+                end
+            end
+        end
+    else
+        parsing_error('didn''t expect to arrive here', line, node_to_parse);
+    end
+
+    names = Xtmp.name;
+    for j = length(names):-1:1
+        % Handle constraits
+        if any(strcmp(X.name, names{j}))
+            X.(names{j}) = X.(names{j}) + Xtmp.(names{j});
+            Xtmp = Xtmp.remove(names{j});
+        end
+    end
+    X = [X Xtmp];
+end
+Y = Y - lhssub;
+
+%% Set start and end dates
+fp = Y.firstobservedperiod;
+lp = Y.lastobservedperiod;
+if ~isempty(X)
+    % X is empty when AR(1) without parameter is encountered
+    fp = max(fp, X.firstobservedperiod);
+    lp = min(lp, X.lastobservedperiod);
+end
+if ~isempty(lhssub)
+    fp = max(fp, lhssub.firstobservedperiod);
+    lp = min(lp, lhssub.lastobservedperiod);
+end
+
+% If it exists, account for tag set in mod file
+if isfield(ast, 'tags') ...
+        && isfield(ast.tags, 'sample') ...
+        && ~isempty(ast.tags.sample)
+    colon_idx = strfind(ast.tags.sample, ':');
+    fsd = dates(ast.tags.sample(1:colon_idx-1));
+    lsd = dates(ast.tags.sample(colon_idx+1:end));
+    if fp > fsd
+        warning(['The sample over which you want to estimate contains NaNs. '...
+            'Adjusting estimation range to begin on: ' fp.char])
+    else
+        fp = fsd;
+    end
+    if lp < lsd
+        warning(['The sample over which you want to estimate contains NaNs. '...
+            'Adjusting estimation range to end on: ' lp.char])
+    else
+        lp = lsd;
+    end
+end
+
+Y = Y(fp:lp);
+if ~isempty(X)
+    X = X(fp:lp);
+    names = X.name;
+    for i = 1:length(names)
+        if all(X.(names{i}).data == 0)
+            X = X.remove(names{i});
+        end
+    end
+end
+if ~isempty(lhssub)
+    lhssub = lhssub(fp:lp);
+end
+end
+
+%% Helper Functions
+function parsing_error(msg, line, node)
+if nargin == 3 && ~isempty(node)
+    error('\nERROR encountered parsing `%s` in equation on line %d: %s\n', printNode(node), line, msg);
+else
+    error('\nERROR encountered parsing of equation on line %d: %s\n', line, msg)
+end
+end
+
+function str = printNode(node)
+if strcmp(node.node_type, 'NumConstNode')
+    str = num2str(node.value);
+elseif strcmp(node.node_type, 'VariableNode')
+    if strcmp(node.type, 'endogenous') || strcmp(node.type, 'exogenous')
+        str = node.name;
+        if node.lag ~= 0
+            str = [str '(' num2str(node.lag) ')'];
+        end
+    elseif strcmp(node.type, 'parameter')
+        str = node.name;
+    end
+elseif strcmp(node.node_type, 'UnaryOpNode')
+    str = printNode(node.arg);
+    str = [node.op '(' str ')'];
+elseif strcmp(node.node_type, 'BinaryOpNode')
+    str = ['(' printNode(node.arg1) node.op printNode(node.arg2) ')'];
+end
+end
+
+function terms = decomposeAdditiveTerms(terms, node, node_sign)
+if strcmp(node.node_type, 'NumConstNode') || strcmp(node.node_type, 'VariableNode')
+    terms = [terms {{node node_sign}}];
+elseif strcmp(node.node_type, 'UnaryOpNode')
+    if strcmp(node.op, 'uminus')
+        terms = decomposeAdditiveTerms(terms, node.arg, -node_sign);
+    else
+        terms = [terms {{node node_sign}}];
+    end
+elseif strcmp(node.node_type, 'BinaryOpNode')
+    if strcmp(node.op, '+') || strcmp(node.op, '-')
+        terms = decomposeAdditiveTerms(terms, node.arg1, node_sign);
+        if strcmp(node.op, '+')
+            terms = decomposeAdditiveTerms(terms, node.arg2, node_sign);
+        else
+            terms = decomposeAdditiveTerms(terms, node.arg2, -node_sign);
+        end
+    else
+        terms = [terms {{node node_sign}}];
+    end
+else
+    terms = [terms {{node node_sign}}];
+end
+end
+
+function [X, pterms] = parseTimesNode(ds, node, line)
+% Separate the parameter expression from the endogenous expression
+assert(strcmp(node.node_type, 'BinaryOpNode') && strcmp(node.op, '*'))
+if isOlsParamExpr(node.arg1, line)
+    pterms = decomposeAdditiveTerms([], node.arg1, 1);
+    X = evalNode(ds, node.arg2, line, dseries());
+elseif isOlsParamExpr(node.arg2, line)
+    pterms = decomposeAdditiveTerms([], node.arg2, 1);
+    X = evalNode(ds, node.arg1, line, dseries());
+else
+    parsing_error('expecting (param expr)*(var expr)', line, node);
+end
+if strcmp(pterms{1}{1}.node_type, 'NumConstNode')
+    X = X.rename(num2str(pterms{1}{1}.value));
+elseif strcmp(pterms{1}{1}.node_type, 'VariableNode')
+    X = X.rename(pterms{1}{1}.name);
+else
+    parsing_error('unexpected type', line, node)
+end
+for ii = 2:length(pterms)
+    if strcmp(pterms{ii}{1}.node_type, 'NumConstNode')
+        X = [X dseries(X{1}.data, X{1}.firstdate, num2str(pterms{ii}{1}.value))];
+    elseif strcmp(pterms{ii}{1}.node_type, 'VariableNode')
+        X = [X dseries(X{1}.data, X{1}.firstdate, pterms{ii}{1}.name)];
+    else
+        parsing_error('unexpected type', line, node)
+    end
+end
+end
+
+function tf = isBaseVarLagEqualToZero(node)
+if strcmp(node.node_type, 'VariableNode')
+    tf = node.lag == 0;
+elseif strcmp(node.node_type, 'UnaryOpNode')
+    tf = isBaseVarLagEqualToZero(node.arg);
+else
+    tf = false;
+end
+end
+
+function tf = isOlsVar(ds, node)
+if strcmp(node.node_type, 'VariableNode') ...
+        && (strcmp(node.type, 'endogenous') ...
+        || (strcmp(node.type, 'exogenous') && any(strcmp(ds.name, node.name))))
+    tf = true;
+elseif strcmp(node.node_type, 'UnaryOpNode')
+    tf = isOlsVar(ds, node.arg);
+else
+    tf = false;
+end
+end
+
+function X = evalNode(ds, node, line, X)
+global M_
+if strcmp(node.node_type, 'NumConstNode')
+    X = dseries(node.value, ds.dates, 'const');
+elseif strcmp(node.node_type, 'VariableNode')
+    if strcmp(node.type, 'endogenous') ...
+            || (strcmp(node.type, 'exogenous') && any(strcmp(ds.name, node.name)))
+        if ds.exist(node.name)
+            X = ds.(node.name)(node.lag);
+        else
+            error('Variable %s is not available in the database.', node.name)
+        end
+    elseif strcmp(node.type, 'parameter')
+        X = M_.params(not(cellfun('isempty', strfind(M_.param_names, node.name))));
+        if isnan(X) || isinf(X) || ~isreal(X)
+            parsing_error(['Value incorrectly set for parameter: ' node.name], line);
+        end
+    end
+elseif strcmp(node.node_type, 'UnaryOpNode')
+    Xtmp = evalNode(ds, node.arg, line, X);
+    % Only works if dseries supports . notation for unary op (true for log/diff)
+    % Otherwise, use: X = eval([node.op '(Xtmp)']);
+    try
+        if strcmp(node.op, 'uminus')
+            X = -Xtmp;
+        else
+            X = Xtmp.(node.op);
+        end
+        if any(isinf(X)) || ~isreal(X)
+            parsing_error(['Error applying ' node.op], line, node);
+        end
+    catch
+        parsing_error(['Error applying ' node.op], line, node);
+    end
+elseif strcmp(node.node_type, 'BinaryOpNode')
+    Xtmp1 = evalNode(ds, node.arg1, line, X);
+    Xtmp2 = evalNode(ds, node.arg2, line, X);
+    switch node.op
+        case '*'
+            Xtmp = Xtmp1 * Xtmp2;
+        case '/'
+            Xtmp = Xtmp1 / Xtmp2;
+        case '+'
+            Xtmp = Xtmp1 + Xtmp2;
+        case '-'
+            Xtmp = Xtmp1 - Xtmp2;
+        otherwise
+            parsing_error(['got unexpected binary op ' node.op], line, node);
+    end
+    if any(isinf(Xtmp)) || ~isreal(Xtmp)
+        parsing_error(['Error applying ' node.op], line, node);
+    end
+    X = X + Xtmp;
+else
+    parsing_error(['got unexpected node type ' node.node_type], line, node);
+end
+end
+
+function tf = isOlsParamExpr(node, line)
+if strcmp(node.node_type, 'NumConstNode')
+    tf = true;
+elseif strcmp(node.node_type, 'VariableNode')
+    if strcmp(node.type, 'parameter')
+        tf = true;
+    else
+        tf = false;
+    end
+elseif strcmp(node.node_type, 'UnaryOpNode')
+    tf = false;
+elseif strcmp(node.node_type, 'BinaryOpNode')
+    tf = isOlsParamExpr(node.arg1, line) && isOlsParamExpr(node.arg2, line);
+    if tf && ~strcmp(node.op, '-')
+        parsing_error(['got unexpected op ' node.op], line, node);
+    end
+else
+    parsing_error(['got unexpected type ' node.node_type], line, node);
+end
+end
+
+function tf = containsParameter(node, line)
+if strcmp(node.node_type, 'NumConstNode')
+    tf = false;
+elseif strcmp(node.node_type, 'VariableNode')
+    if strcmp(node.type, 'parameter')
+        tf = true;
+    else
+        tf = false;
+    end
+elseif strcmp(node.node_type, 'UnaryOpNode')
+    tf = containsParameter(node.arg, line);
+elseif strcmp(node.node_type, 'BinaryOpNode')
+    tf = containsParameter(node.arg1, line) || containsParameter(node.arg2, line);
+else
+    parsing_error(['got unexpected type ' node.node_type], line, node);
+end
+end
diff --git a/matlab/ols/pooled_fgls.m b/matlab/ols/pooled_fgls.m
new file mode 100644
index 0000000000000000000000000000000000000000..ef0fd1cc5fe4f9ca596753fa19278eb23f19ee1f
--- /dev/null
+++ b/matlab/ols/pooled_fgls.m
@@ -0,0 +1,131 @@
+function pooled_fgls(ds, param_common, param_regex, eqtags, model_name, param_names, ds_range)
+% function pooled_fgls(ds, param_common, param_regex, eqtags, model_name, param_names, ds_range)
+% Run Pooled FGLS
+%
+% INPUTS
+%   ds            [dseries]      data to use in estimation
+%   param_common  [cellstr]      List of values to insert into param_regex,
+%                                e.g. country codes {'FR', 'DE', 'IT'}
+%   param_regex   [cellstr]      Where '*' should be replaced by the first
+%                                value in param_common
+%   eqtags        [cellstr]      names of equation tags to estimate. If empty,
+%                                estimate all equations
+%   model_name    [string]       name to use in oo_ and inc file
+%
+%   param_names   [cellstr]      list of parameters to estimate (if
+%                                empty, estimate all) (may contain regex
+%                                to match param_regex)
+%   ds_range      [dates]   range of dates to use in estimation
+%
+% OUTPUTS
+%   none
+%
+% SPECIAL REQUIREMENTS
+%   dynare must have been run with the option: json=compute
+
+% Copyright (C) 2017-2019 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/>.
+
+global M_ oo_
+
+%% Check input arguments
+if nargin < 1 || nargin > 7
+    error('Incorrect number of arguments')
+end
+
+if isempty(ds) || ~isdseries(ds)
+    error('The first argument must be a dseries');
+end
+
+if nargin < 7
+    ds_range = ds.dates;
+end
+
+if nargin < 6
+    param_names = {};
+end
+
+if nargin < 5
+    model_name = '';
+end
+
+if nargin < 4
+    eqtags = {};
+end
+
+maxit = 100;
+tol = 1e-6;
+
+%% Common work between pooled_ols and pooled_fgls
+[Y, X, pbeta, residnames, country_name, model_name] = pooled_ols(ds, param_common, param_regex, true, eqtags, model_name, param_names, ds_range);
+
+%% Estimation
+neqs = length(residnames);
+oo_.pooled_fgls.(model_name).dof = size(X,1)/neqs;
+beta0 = oo_.pooled_fgls.(model_name).beta;
+for i = 1:maxit
+    resid = Y - X * beta0;
+    resid = reshape(resid, oo_.pooled_fgls.(model_name).dof, neqs);
+    vcv = resid'*resid/oo_.pooled_fgls.(model_name).dof;
+    kLeye = kron(inv(chol(vcv))', eye(oo_.pooled_fgls.(model_name).dof));
+    [q, r] = qr(kLeye*X, 0);
+    oo_.pooled_fgls.(model_name).beta = r\(q'*kLeye*Y);
+    if max(abs(beta0 - oo_.pooled_fgls.(model_name).beta)) < tol
+        break
+    end
+    beta0 = oo_.pooled_fgls.(model_name).beta;
+    if i == maxit
+        warning('maximum nuber of iterations reached')
+    end
+end
+
+% Set appropriate entries in M_.Sigma_e
+idxs = zeros(neqs, 1);
+for i = 1:neqs
+    idxs(i) = find(strcmp(residnames{i}, M_.exo_names));
+end
+M_.Sigma_e(idxs, idxs) = vcv;
+
+regexcountries = ['(' strjoin(param_common(1:end),'|') ')'];
+assigned_idxs = false(size(pbeta));
+incidxs = [];
+for i = 1:length(param_regex)
+    beta_idx = strcmp(pbeta, strrep(param_regex{i}, '*', country_name));
+    assigned_idxs = assigned_idxs | beta_idx;
+    value = oo_.pooled_fgls.(model_name).beta(beta_idx);
+    if isempty(eqtags) && isempty(param_names)
+        assert(~isempty(value));
+    end
+    if ~isempty(value)
+        idxs = find(~cellfun(@isempty, regexp(M_.param_names, strrep(param_regex{i}, '*', regexcountries))))';
+        incidxs = [incidxs idxs];
+        M_.params(idxs) = value;
+    end
+end
+idxs = find(assigned_idxs == 0);
+values = oo_.pooled_fgls.(model_name).beta(idxs);
+names = pbeta(idxs);
+assert(length(values) == length(names));
+for i = 1:length(idxs)
+    incidxs = [incidxs find(strcmp(M_.param_names, names{i}))];
+    M_.params(incidxs(end)) = values(i);
+end
+
+% Write .inc file
+write_param_init_inc_file('pooled_fgls', model_name, incidxs, M_.params(incidxs));
+
+end
diff --git a/matlab/ols/pooled_ols.m b/matlab/ols/pooled_ols.m
new file mode 100644
index 0000000000000000000000000000000000000000..e47d77646265136e9b30b55de4dd1b63f17189e3
--- /dev/null
+++ b/matlab/ols/pooled_ols.m
@@ -0,0 +1,236 @@
+function varargout = pooled_ols(ds, param_common, param_regex, overlapping_dates, eqtags, model_name, param_names, ds_range)
+% function varargout = pooled_ols(ds, param_common, param_regex, overlapping_dates, eqtags, model_name, param_names, ds_range)
+% Run Pooled OLS
+% Apply parameter values found to corresponding parameter values in the
+% other blocks of the model
+%
+% INPUTS
+%   ds                  [dseries]  data to use in estimation
+%   param_common        [cellstr]  List of values to insert into param_regex,
+%                                  e.g. country codes {'FR', 'DE', 'IT'}
+%   param_regex         [cellstr]  Where '*' should be replaced by the first
+%                                  value in param_common
+%   overlapping_dates   [bool]     if the dates across the equations should
+%                                  overlap
+%   eqtags              [cellstr]  names of equation tags to estimate. If empty,
+%                                  estimate all equations
+%   model_name          [string]   name to use in oo_ and inc file
+%   param_names         [cellstr]  list of parameters to estimate (if
+%                                  empty, estimate all) (may contain regex
+%                                  to match param_regex)
+%   ds_range             [dates]   range of dates to use in estimation
+%
+% OUTPUTS
+%   return arguments common to pooled_fgls only if called from pooled_fgls
+%   
+%
+% SPECIAL REQUIREMENTS
+%   dynare must have been run with the option: json=compute
+
+% Copyright (C) 2017-2019 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/>.
+
+global M_ oo_
+
+%% Check input arguments
+if nargin < 1 || nargin > 8
+    error('Incorrect number of arguments')
+end
+
+if isempty(ds) || ~isdseries(ds)
+    error('The first argument must be a dseries');
+end
+
+if nargin < 8
+    ds_range = ds.dates;
+else
+    if isempty(ds_range)
+        ds_range = ds.dates;
+    else
+        if ds_range(1) < ds.firstdate || ds_range(end) > lastdate(ds)
+            error('There is a problem with the 8th argument: the date range does not correspond to that of the dseries')
+        end
+    end
+end
+
+if nargin < 7
+    param_names = {};
+else
+    if ~isempty(param_names) && ~iscellstr(param_names)
+        error('The 7th argument, if provided, must be a cellstr')
+    end
+end
+
+st = dbstack(1);
+if strcmp(st(1).name, 'pooled_fgls')
+    save_structure_name = 'pooled_fgls';
+else
+    save_structure_name = 'pooled_ols';
+end
+
+if nargin < 6 || isempty(model_name)
+    if ~isfield(oo_, save_structure_name)
+        model_name = [save_structure_name '_model_number_1'];
+    else
+        model_name = [save_structure_name '_model_number_' num2str(length(fieldnames(oo_.(save_structure_name))) + 1)];
+    end
+else
+    if ~isvarname(model_name)
+        error('The 7th argument must be a valid string');
+    end
+end
+
+if nargin < 5
+    eqtags = {};
+end
+
+if isempty(param_common) && isempty(param_regex)
+    disp('Performing OLS instead of Pooled OLS...')
+    dyn_ols(ds, {}, eqtags, model_name, param_names, ds_range);
+    return
+end
+
+assert(~isempty(param_common) && iscellstr(param_common), 'The second argument must be a cellstr');
+assert(~isempty(param_regex) && iscellstr(param_regex), 'The third argument must be a cellstr');
+
+if nargin < 4
+    overlapping_dates = false;
+else
+    assert(islogical(overlapping_dates) && length(overlapping_dates) == 1, 'The fourth argument must be a bool');
+end
+
+
+
+%% Get Equation(s)
+ast = get_ast(eqtags);
+neqs = length(ast);
+
+%% Replace parameter names in equations
+country_name = param_common{1};
+regexcountries = ['(' strjoin(param_common(2:end),'|') ')'];
+ast = replace_parameters(ast, country_name, regexcountries, param_regex);
+
+%% Replace in param_names
+for i = 1:length(param_names)
+    param_names{i} = strrep(param_names{i}, '*', country_name);
+end
+
+%% Find parameters and variable names in every equation & Setup estimation matrices
+[Y, lhssub, X, ~, ~, residnames] = common_parsing(ds(ds_range), ast, overlapping_dates, param_names);
+clear ast
+nobs = zeros(length(Y), 1);
+nobs(1) = Y{1}.nobs;
+fp = Y{1}.firstobservedperiod;
+for i = 2:length(Y)
+    if Y{i}.firstobservedperiod < fp
+        fp = Y{i}.firstobservedperiod;
+    end
+    nobs(i) = Y{i}.nobs;
+end
+[Y, ~, X] = put_in_sur_form(Y, lhssub, X);
+
+%% Handle FGLS
+if strcmp(st(1).name, 'pooled_fgls')
+    % Pass vars back to pooled_fgls
+    varargout{1} = Y.data;
+    varargout{2} = X.data;
+    varargout{3} = X.name;
+    varargout{4} = residnames;
+    varargout{5} = country_name;
+    varargout{6} = model_name;
+end
+
+%% Estimation
+% Estimated Parameters
+[q, r] = qr(X.data, 0);
+oo_.(save_structure_name).(model_name).beta = r\(q'*Y.data);
+
+if strcmp(st(1).name, 'pooled_fgls')
+    return
+end
+clear save_structure_name;
+
+% Assign parameter values back to parameters using param_regex & param_common
+regexcountries = ['(' strjoin(param_common(1:end),'|') ')'];
+assigned_idxs = false(size(X.name));
+incidxs = [];
+for i = 1:length(param_regex)
+    beta_idx = strcmp(X.name, strrep(param_regex{i}, '*', country_name));
+    assigned_idxs = assigned_idxs | beta_idx;
+    value = oo_.pooled_ols.(model_name).beta(beta_idx);
+    if isempty(eqtags) && isempty(param_names)
+        assert(~isempty(value));
+    end
+    if ~isempty(value)
+        idxs = find(~cellfun(@isempty, regexp(M_.param_names, strrep(param_regex{i}, '*', regexcountries))))';
+        incidxs = [incidxs idxs];
+        M_.params(idxs) = value;
+    end
+end
+idxs = find(assigned_idxs == 0);
+values = oo_.pooled_ols.(model_name).beta(idxs);
+names = X.name(idxs);
+assert(length(values) == length(names));
+for i = 1:length(idxs)
+    incidxs = [incidxs find(strcmp(M_.param_names, names{i}))];
+    M_.params(incidxs(end)) = values(i);
+end
+
+% Write .inc file
+write_param_init_inc_file('pooled_ols', model_name, incidxs, M_.params(incidxs));
+
+residuals = Y.data - X.data * oo_.pooled_ols.(model_name).beta;
+for i = 1:neqs
+    if i == 1
+        oo_.pooled_ols.(model_name).resid.(residnames{i}) = residuals(1:nobs(1));
+    elseif i == neqs
+        oo_.pooled_ols.(model_name).resid.(residnames{i}) = residuals(sum(nobs(1:i-1))+1:end);
+    else
+        oo_.pooled_ols.(model_name).resid.(residnames{i}) = residuals(sum(nobs(1:i-1))+1:sum(nobs(1:i)));
+    end
+    oo_.pooled_ols.(model_name).varcovar.(['eq' num2str(i)]) = oo_.pooled_ols.(model_name).resid.(residnames{i})*oo_.pooled_ols.(model_name).resid.(residnames{i})';
+    idx = find(strcmp(residnames{i}, M_.exo_names));
+    M_.Sigma_e(idx, idx) = var(oo_.pooled_ols.(model_name).resid.(residnames{i}));
+end
+end
+
+function ast = replace_parameters(ast, country_name, regexcountries, param_regex)
+for i = 1:length(ast)
+    ast{i}.AST = replace_parameters_recursive(ast{i}.AST, country_name, regexcountries, param_regex);
+end
+end
+
+function node = replace_parameters_recursive(node, country_name, regexcountries, param_regex)
+if strcmp(node.node_type, 'VariableNode')
+    if strcmp(node.type, 'parameter')
+        for i = 1:length(param_regex)
+            splitp = strsplit(param_regex{i}, '*');
+            assert(length(splitp) >= 2);
+            tmp = regexprep(node.name, strjoin(splitp, regexcountries), strjoin(splitp, country_name));
+            if ~strcmp(tmp, node.name)
+                node.name = tmp;
+                return
+            end
+        end
+    end
+elseif strcmp(node.node_type, 'UnaryOpNode')
+    node.arg = replace_parameters_recursive(node.arg, country_name, regexcountries, param_regex);
+elseif strcmp(node.node_type, 'BinaryOpNode')
+    node.arg1 = replace_parameters_recursive(node.arg1, country_name, regexcountries, param_regex);
+    node.arg2 = replace_parameters_recursive(node.arg2, country_name, regexcountries, param_regex);
+end
+end
diff --git a/matlab/ols/put_in_sur_form.m b/matlab/ols/put_in_sur_form.m
new file mode 100644
index 0000000000000000000000000000000000000000..40cb0ed08d6285493c08180ff8b037922e139eac
--- /dev/null
+++ b/matlab/ols/put_in_sur_form.m
@@ -0,0 +1,93 @@
+function [Yvec, lhssubvec, Xmat, constrained] = put_in_sur_form(Y, lhssub, X)
+%function [Yvec, lhssubvec, Xmat, constrained] = put_in_sur_form(Y, lhssub, X)
+%
+% INPUTS
+%   Y           [cell array]  dependent variables
+%   lhssub      [cell array]  RHS subtracted from LHS
+%   X           [cell array]  regressors
+%
+% OUTPUTS
+%   Yvec        [vector]      dependent variables
+%   lhssubvec   [cell array]  RHS subtracted from LHS
+%   Xmat        [matrix]      regressors
+%   constrained [cellstr]     names of parameters that were constrained
+%
+% SPECIAL REQUIREMENTS
+%   none
+
+% Copyright (C) 2019 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/>.
+
+%% Check inputs
+if nargin ~= 3
+    error('function expects 3 arguments');
+end
+
+if isempty(Y) || ~iscell(Y) ...
+        || isempty(lhssub) || ~iscell(lhssub) ...
+        || isempty(X) || ~iscell(X) ...
+        || length(Y) ~= length(X) ...
+        || length(Y) ~= length(lhssub)
+    error('function arguments should be cells of the same size');
+end
+
+%% Organize output
+neqs = length(Y);
+nobs = zeros(neqs, 1);
+for i = 1:neqs
+    if ~isempty(X{i})
+        % X{i} is empty for AR(1) equations
+        assert(size(X{i}, 1) == size(Y{i}, 1), 'Y{i} and X{i} must have the same nuber of observations');
+    end
+    nobs(i) = size(Y{i}, 1);
+end
+fd = Y{1}.firstdate;
+nrows = sum(nobs);
+Xmat = dseries();
+Yvec = dseries();
+lhssubvec = dseries();
+constrained = {};
+for i = 1:neqs
+    if ~isempty(X{i})
+        to_remove = [];
+        nr = sum(nobs(1:i-1));
+        nxcol = size(X{i}, 2);
+        names = X{i}.name;
+        Xtmp = dseries([zeros(nr, nxcol); X{i}.data; zeros(nrows-nr-nobs(i), nxcol)], fd, names);
+        Xmatnames = Xmat.name;
+        for j = 1:length(names)
+            idx = find(strcmp(Xmatnames, names{j}));
+            if ~isempty(idx)
+                Xmat.(Xmatnames{idx}) = Xmat.(Xmatnames{idx}) + Xtmp.(names{j});
+                Xtmp = Xtmp.remove(names{j});
+                constrained{end+1} = Xmatnames{idx};
+            end
+        end
+        if ~isempty(Xtmp)
+            Xmat = [Xmat Xtmp];
+        end
+    end
+    Yvec = dseries([Yvec.data; Y{i}.data], fd);
+    if isempty(lhssub{i})
+        lhssubvec = dseries([lhssubvec.data; zeros(size(Y{i}.data, 1), 1)], fd);
+    else
+        lhssubvec = dseries([lhssubvec.data; lhssub{i}.data], fd);
+    end
+end
+assert(size(Yvec, 1) == size(Xmat, 1));
+assert(size(Yvec, 1) == size(lhssubvec, 1));
+end
diff --git a/matlab/ols/sur.m b/matlab/ols/sur.m
new file mode 100644
index 0000000000000000000000000000000000000000..0f3b7ccb58d59e6d9d50684c909140f931d28d18
--- /dev/null
+++ b/matlab/ols/sur.m
@@ -0,0 +1,258 @@
+function varargout = sur(ds, param_names, eqtags, model_name, noniterative, ds_range)
+
+% Seemingly Unrelated Regressions
+%
+% INPUTS
+%   ds                [dseries]    data to use in estimation
+%   param_names       [cellstr]    list of parameters to estimate
+%   eqtags            [cellstr]    names of equation tags to estimate. If empty,
+%                                  estimate all equations
+%   model_name        [string]     name of model to be displayed with
+%                                  report
+%   noniterative      [bool]       if true use noniterative estimation method
+%   ds_range          [dates]      range of dates to use in estimation
+%
+% OUTPUTS
+%   none
+%
+% SPECIAL REQUIREMENTS
+%   dynare must have been run with the option: json=compute
+
+% Copyright (C) 2017-2020 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/>.
+
+global M_ oo_ options_
+
+%
+% Check inputs
+%
+
+if nargin < 1 || nargin > 6
+    error('function takes between 1 and 6 arguments');
+end
+
+if isempty(ds) || ~isdseries(ds)
+    error('The first argument must be a dseries');
+end
+
+if nargin < 6
+    ds_range = ds.dates;
+else
+    if isempty(ds_range)
+        ds_range = ds.dates;
+    else
+        if ds_range(1) < ds.firstdate || ds_range(end) > lastdate(ds)
+            error('There is a problem with the 6th argument: the date range does not correspond to that of the dseries')
+        end
+    end
+end
+
+if nargin < 5
+    noniterative = false;
+else
+    if ~islogical(noniterative)
+        error('the fifth argument, if passed, must be a boolean')
+    end
+end
+
+if nargin < 4
+    if ~isfield(oo_, 'sur')
+        model_name = 'sur_model_number_1';
+    else
+        model_name = ['sur_model_number_' num2str(length(fieldnames(oo_.sur)) + 1)];
+    end
+else
+    if ~isvarname(model_name)
+        error('the fourth argument, if passed, must be a string')
+    end
+end
+
+if nargin < 3
+    eqtags = {};
+end
+
+if nargin < 2
+    param_names = {};
+else
+    if ~isempty(param_names) && ~iscellstr(param_names)
+        error('the 2nd argument must be a cellstr')
+    end
+end
+
+maxit = 100;
+tol = 1e-6;
+
+%
+% Get Equation(s)
+%
+
+ast = handle_constant_eqs(get_ast(eqtags));
+neqs = length(ast);
+
+%
+% Find parameters and variable names in equations and setup estimation matrices
+%
+
+[Y, lhssub, X, fp, lp, residnames] = common_parsing(ds(ds_range), ast, true, param_names);
+clear ast
+nobs = Y{1}.nobs;
+[Y, lhssub, X, constrained] = put_in_sur_form(Y, lhssub, X);
+
+if nargin == 1 && size(X, 2) ~= M_.param_nbr
+    warning(['Not all parameters were used in model: ' strjoin(setdiff(M_.param_names, X.name), ', ')]);
+end
+
+%
+% Return to surgibbs if called from there
+%
+
+st = dbstack(1);
+if ~isempty(st) && strcmp(st(1).name, 'surgibbs')
+    varargout{1} = nobs;
+    varargout{2} = X{param_names{:}}.data;
+    varargout{3} = Y.data;
+    varargout{4} = neqs;
+    varargout{5} = lhssub.data;
+    varargout{6} = fp{1};
+    varargout{7} = lp{1};
+    return
+end
+
+% constrained_param_idxs: indexes in X.name of parameters that were constrained
+constrained_param_idxs = NaN(length(constrained), 1);
+j = 0;
+for i = 1:length(constrained)
+    idx = find(strcmp(X.name, constrained{i}));
+    if ~isempty(idx)
+        j = j+1;
+        constrained_param_idxs(j, 1) = idx;
+    end
+end
+constrained_param_idxs = constrained_param_idxs(1:j);
+
+%
+% Estimation
+%
+
+oo_.sur.(model_name).dof = nobs;
+
+% Estimated Parameters
+[q, r] = qr(X.data, 0);
+xpxi = (r'*r)\eye(size(X.data, 2));
+beta0 = (r\(q'*Y.data));
+for i = 1:maxit
+    resid = Y.data - X.data * beta0;
+    resid = reshape(resid, oo_.sur.(model_name).dof, neqs);
+    vcv = resid'*resid/oo_.sur.(model_name).dof;
+    kLeye = kron(inv(chol(vcv))', eye(oo_.sur.(model_name).dof));
+    [q, r] = qr(kLeye*X.data, 0);
+    oo_.sur.(model_name).beta = r\(q'*kLeye*Y.data);
+    if noniterative || max(abs(beta0 - oo_.sur.(model_name).beta)) < tol
+        break
+    end
+    beta0 = oo_.sur.(model_name).beta;
+    if i == maxit
+        warning('maximum nuber of iterations reached')
+    end
+end
+
+% Set appropriate entries in M_.Sigma_e
+idxs = zeros(length(residnames), 1);
+for i = 1:length(residnames)
+    idxs(i) = find(strcmp(residnames{i}, M_.exo_names));
+end
+M_.Sigma_e(idxs, idxs) = vcv;
+
+% opidxs: indexes in M_.params associated with columns of X
+opidxs = zeros(X.vobs, 1);
+for i = 1:X.vobs
+    opidxs(i, 1) = find(strcmp(X.name{i}, M_.param_names));
+end
+
+% Set params
+M_.params(opidxs) = oo_.sur.(model_name).beta;
+
+% Write .inc file
+write_param_init_inc_file('sur', model_name, opidxs, oo_.sur.(model_name).beta);
+
+% Yhat
+oo_.sur.(model_name).Yhat = X.data * oo_.sur.(model_name).beta;
+oo_.sur.(model_name).YhatOrig = oo_.sur.(model_name).Yhat;
+oo_.sur.(model_name).Yobs = Y;
+
+% Residuals
+oo_.sur.(model_name).resid = Y.data - oo_.sur.(model_name).Yhat;
+
+% Correct Yhat reported back to user
+oo_.sur.(model_name).Yhat = oo_.sur.(model_name).Yhat + lhssub;
+yhatname = [model_name '_FIT'];
+ds.(yhatname) = dseries(oo_.sur.(model_name).Yhat.data,  fp{1}, yhatname);
+varargout{1} = ds;
+
+%
+% Calculate various statistics
+%
+
+% Estimate for sigma^2
+SS_res = oo_.sur.(model_name).resid'*oo_.sur.(model_name).resid;
+oo_.sur.(model_name).s2 = SS_res/oo_.sur.(model_name).dof;
+
+% System R^2 value of McElroy (1977) - formula from Judge et al. (1986, p. 477)
+oo_.sur.(model_name).R2 = 1 - (oo_.sur.(model_name).resid' * kron(inv(M_.Sigma_e(idxs,idxs)), eye(nobs)) * oo_.sur.(model_name).resid) ...
+                            / (oo_.sur.(model_name).Yobs.data' * kron(inv(M_.Sigma_e(idxs,idxs)), eye(nobs)-ones(nobs,nobs)/nobs) * oo_.sur.(model_name).Yobs.data);
+
+% Adjusted R^2
+oo_.sur.(model_name).adjR2 = 1 - (1 - oo_.sur.(model_name).R2) * ((neqs*nobs-neqs)/(neqs*nobs-size(oo_.sur.(model_name).beta,1)));
+
+% Durbin-Watson
+ediff = oo_.sur.(model_name).resid(2:oo_.sur.(model_name).dof) - oo_.sur.(model_name).resid(1:oo_.sur.(model_name).dof - 1);
+oo_.sur.(model_name).dw = (ediff'*ediff)/SS_res;
+
+% Standard Error
+oo_.sur.(model_name).stderr = sqrt(oo_.sur.(model_name).s2*diag(xpxi));
+
+% T-Stat
+oo_.sur.(model_name).tstat = oo_.sur.(model_name).beta./oo_.sur.(model_name).stderr;
+
+oo_.sur.(model_name).neqs = neqs;
+oo_.sur.(model_name).pname = X.name;
+
+%
+% Print Output
+%
+
+if ~options_.noprint
+    preamble = {['Model name: ' model_name], ...
+        sprintf('No. Equations: %d', oo_.sur.(model_name).neqs), ...
+        sprintf('No. Independent Variables: %d', size(X, 2)), ...
+        sprintf('Observations: %d', oo_.sur.(model_name).dof)};
+
+    afterward = {sprintf('R^2: %f', oo_.sur.(model_name).R2), ...
+        sprintf('R^2 Adjusted: %f', oo_.sur.(model_name).adjR2), ...
+        sprintf('s^2: %f', oo_.sur.(model_name).s2), ...
+        sprintf('Durbin-Watson: %f', oo_.sur.(model_name).dw)};
+
+    if ~isempty(constrained_param_idxs)
+        afterward = [afterward, ['Constrained parameters: ' ...
+            strjoin(X.name(constrained_param_idxs), ', ')]];
+    end
+
+    dyn_table('SUR Estimation', preamble, afterward, X.name, ...
+        {'Estimates','t-statistic','Std. Error'}, 4, ...
+        [oo_.sur.(model_name).beta oo_.sur.(model_name).tstat oo_.sur.(model_name).stderr]);
+end
+end
diff --git a/matlab/ols/write_param_init_inc_file.m b/matlab/ols/write_param_init_inc_file.m
new file mode 100644
index 0000000000000000000000000000000000000000..2ce84f0bad0030bcde78500687f56ad67d6bac2c
--- /dev/null
+++ b/matlab/ols/write_param_init_inc_file.m
@@ -0,0 +1,85 @@
+function write_param_init_inc_file(subfolder, fnameroot, idxs, estimated_params)
+%function write_param_init_inc_file(fname, idxs, estimated_params)
+% Write .inc files that initialize parameters
+%
+% INPUTS
+%   subfolder        [string] subfolder in which to place file
+%   fnameroot        [string] root of filename
+%   idxs             [vector] indexes in M_.params of estimated parameters
+%   estimated_params [vector] estimated parameters  
+%
+% OUTPUTS
+%   none
+%
+% SPECIAL REQUIREMENTS
+%   none
+
+% Copyright (C) 2019 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/>.
+
+global M_
+
+%% Check inputs
+if nargin ~= 4
+    error('function takes 4 arguments')
+end
+
+if ~ischar(subfolder)
+    error([subfolder ' must be a string']);
+end
+
+if ~ischar(fnameroot)
+    error([fnameroot ' must be a string']);
+end
+
+if ~isvector(idxs) ...
+        || ~isvector(estimated_params) ...
+        || length(idxs) ~= length(estimated_params)
+    error('the two arguments must be vectors of the same length')
+end
+
+%% Write file
+% Open
+filepath = [M_.fname filesep 'model' filesep subfolder];
+if ~exist(filepath, 'dir')
+    mkdir(filepath)
+end
+
+fname = [filepath filesep fnameroot '-declare.inc'];
+fid = fopen(fname, 'w');
+if fid < 0
+    error(['couldn''t open file' fname])
+end
+
+% Write declaration
+fprintf(fid, 'parameters');
+for i = 1:length(idxs)
+    fprintf(fid, ' %s', M_.param_names{idxs(i)});
+end
+fprintf(fid, ';\n');
+fclose(fid);
+
+fname = [filepath filesep fnameroot '-initialize.inc'];
+fid = fopen(fname, 'w');
+if fid < 0
+    error(['couldn''t open file' fname])
+end
+for i = 1:length(idxs)
+    fprintf(fid, '%s = %f;\n', M_.param_names{idxs(i)}, estimated_params(i));
+end
+fclose(fid);
+end
diff --git a/matlab/olsgibbs.m b/matlab/olsgibbs.m
new file mode 100644
index 0000000000000000000000000000000000000000..43dfef938b527f26fc635f98f488e45670eb0c6a
--- /dev/null
+++ b/matlab/olsgibbs.m
@@ -0,0 +1,279 @@
+function ds = olsgibbs(ds, eqtag, BetaPriorExpectation, BetaPriorVariance, s2, nu, ndraws, discarddraws, thin, fitted_names_dict, model_name, param_names, ds_range)
+%function ds = olsgibbs(ds, eqtag, BetaPriorExpectation, BetaPriorVariance, s2, nu, ndraws, discarddraws, thin, fitted_names_dict, model_name, param_names, ds_range)
+% Implements Gibbs Sampling for univariate linear model.
+%
+% INPUTS
+% - ds                          [dseries]    dataset.
+% - eqtag                       [string]     name of equation tag to estimate.
+% - BetaPriorExpectation        [double]     vector with n elements, prior expectation of β.
+% - BetaPriorVariance           [double]     n*n matrix, prior variance of β.
+% - s2                          [double]     scalar, first hyperparameter for h.
+% - nu                          [integer]    scalar, second hyperparameter for h.
+% - ndraws                      [integer]    scalar, total number of draws (Gibbs sampling)
+% - discarddraws                [integer]    scalar, number of draws to be discarded.
+% - thin                        [integer]    scalar, if thin == N, save every Nth draw (default is 1).
+% - fitted_names_dict           [cell]       Nx2 or Nx3 cell array to be used in naming fitted
+%                                            values; first column is the equation tag,
+%                                            second column is the name of the
+%                                            associated fitted value, third column
+%                                            (if it exists) is the function name of
+%                                            the transformation to perform on the
+%                                            fitted value.
+% - model_name                  [string]     name to use in oo_ and inc file
+% - param_names                 [cellstr]    list of parameters to estimate (if
+%                                            empty, estimate all)
+% - ds_range                    [dates]      range of dates to use in estimation
+%
+% OUTPUTS
+% - ds                          [dseries]    dataset updated with fitted value
+%
+% SPECIAL REQUIREMENTS
+%   dynare must have been run with the option: json=compute
+
+% Copyright (C) 2018-2019 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/>.
+
+global M_ oo_ options_
+
+%% Check input
+if nargin < 7 || nargin > 13
+    error('Incorrect number of arguments')
+end
+
+if isempty(ds) || ~isdseries(ds)
+    error('The 1st argument must be a dseries')
+end
+
+if ~ischar(eqtag)
+    error('The 2nd argument must be a string')
+end
+
+if ~isvector(BetaPriorExpectation)
+    error('The 3rd argument must be a vector')
+else
+    if ~isempty(BetaPriorExpectation)
+        BetaPriorExpectation = transpose(BetaPriorExpectation(:));
+    end
+end
+
+if ~ismatrix(BetaPriorVariance) || length(BetaPriorExpectation)~=length(BetaPriorVariance)
+    error('The 4th argument (BetaPriorVariance) must be a square matrix with the same dimension as the third argument (BetaPriorExpectation)')
+else
+    warning('off', 'MATLAB:singularMatrix')
+    BetaInversePriorVariance = eye(length(BetaPriorVariance))/BetaPriorVariance;
+    warning('on', 'MATLAB:singularMatrix')
+end
+
+if ~isreal(s2)
+    error('The 5th argument (s2) must be a double')
+end
+
+if ~isint(nu)
+    error('The 6th argument (nu) must be an integer')
+end
+
+if ~isint(ndraws)
+    error('The 7th argument (ndraws) must be an integer')
+end
+
+if nargin <= 7
+    discarddraws = 0;
+else
+    if ~isint(discarddraws)
+        error('The 8th argument (discardeddraws), if provided, must be an integer')
+    else
+        if discarddraws >= ndraws
+            error('The 8th argument (discardeddraws) must be smaller than the 7th argument (ndraws)')
+        end
+    end
+end
+
+if nargin <= 8
+    thin = 1;
+else
+    if ~isint(thin)
+        error('The 9th argument, must be an integer')
+    end
+end
+
+if nargin <= 9
+    fitted_names_dict = {};
+else
+    if ~isempty(fitted_names_dict) && ...
+            (~iscell(fitted_names_dict) || ...
+            (size(fitted_names_dict, 2) < 2 || size(fitted_names_dict, 2) > 3))
+        error('The 10th argument must be an Nx2 or Nx3 cell array');
+    end
+end
+
+if nargin <= 10
+    model_name = eqtag;
+else
+    if ~isvarname(model_name)
+        error('The 11th argument must be a valid string');
+    end
+end
+
+if nargin <= 11
+    param_names = {};
+else
+    if ~isempty(param_names) && ~iscellstr(param_names)
+        error('The 12th argument, if provided, must be a cellstr')
+    end
+end
+
+if nargin <= 12
+    ds_range = ds.dates;
+else
+    if isempty(ds_range)
+        ds_range = ds.dates;
+    else
+        if ds_range(1) < ds.firstdate || ds_range(end) > lastdate(ds)
+            error('There is a problem with the 13th argument: the date range does not correspond to that of the dseries')
+        end
+    end
+end
+
+%% Parse equation
+[Y, lhssub, X, fp, lp] = common_parsing(ds(ds_range), get_ast({eqtag}), true, param_names);
+lhsname = Y{1}.name;
+Y = Y{1}.data;
+X = X{1};
+fp = fp{1};
+lp = lp{1};
+pnames = X.name;
+N = size(X.data, 1);
+X = X.data;
+
+%% Estimation (see Koop, Gary. Bayesian Econometrics. 2003. Chapter 4.2)
+PosteriorDegreesOfFreedom = N + nu;
+n = length(pnames);
+assert(n==length(BetaPriorExpectation), 'the length prior mean for beta must be the same as the number of parameters in the equation to be estimated.');
+h = 1.0/s2*nu; % Initialize h to the prior expectation.
+
+periods = 1;
+linee = 1;
+
+% Posterior Simulation
+oo_.olsgibbs.(model_name).draws = zeros(floor((ndraws-discarddraws)/thin), n+3);
+for i=1:discarddraws
+    % Set conditional distribution of β
+    InverseConditionalPoseriorVariance = BetaInversePriorVariance + h*(X'*X);
+    cholConditionalPosteriorVariance = chol(InverseConditionalPoseriorVariance\eye(n), 'upper');
+    ConditionalPosteriorExpectation = (BetaPriorExpectation*BetaInversePriorVariance + h*(Y'*X))/InverseConditionalPoseriorVariance;
+    % Draw beta | Y, h
+    beta = rand_multivariate_normal(ConditionalPosteriorExpectation, cholConditionalPosteriorVariance, n);
+    % draw h | Y, beta
+    resids = Y - X*transpose(beta);
+    s2_ = (resids'*resids + nu*s2)/PosteriorDegreesOfFreedom;
+    h = gamrnd(PosteriorDegreesOfFreedom/2.0, 2.0/(PosteriorDegreesOfFreedom*s2_));
+end
+
+hh = dyn_waitbar(0,'Please wait. Gibbs sampler...');
+set(hh,'Name','Olsgibbs estimation.');
+for i = discarddraws+1:ndraws
+    if ~mod(i,10)
+        dyn_waitbar((i-discarddraws)/(ndraws-discarddraws),hh,'Please wait. Gibbs sampler...');
+    end
+    % Set conditional distribution of β
+    InverseConditionalPoseriorVariance = BetaInversePriorVariance + h*(X'*X);
+    cholConditionalPosteriorVariance = chol(InverseConditionalPoseriorVariance\eye(n), 'upper');
+    ConditionalPosteriorExpectation = (BetaPriorExpectation*BetaInversePriorVariance + h*(Y'*X))/InverseConditionalPoseriorVariance;
+    % Draw beta | Y, h
+    beta = rand_multivariate_normal(ConditionalPosteriorExpectation, cholConditionalPosteriorVariance, n);
+    % draw h | Y, beta
+    resids = Y - X*transpose(beta);
+    s2_ = (resids'*resids + nu*s2)/PosteriorDegreesOfFreedom;
+    h = gamrnd(PosteriorDegreesOfFreedom/2.0, 2.0/(PosteriorDegreesOfFreedom*s2_));
+    R2 = 1-var(resids)/var(Y);
+    if isequal(periods, thin)
+        oo_.olsgibbs.(model_name).draws(linee, 1:n) = beta;
+        oo_.olsgibbs.(model_name).draws(linee, n+1) = h;
+        oo_.olsgibbs.(model_name).draws(linee, n+2) = s2_;
+        oo_.olsgibbs.(model_name).draws(linee, n+3) = R2;
+        periods = 1;
+        linee = linee+1;
+    else
+        periods = periods+1;
+    end
+end
+dyn_waitbar_close(hh);
+
+%% Save posterior moments.
+oo_.olsgibbs.(model_name).posterior.mean.beta = mean(oo_.olsgibbs.(model_name).draws(:,1:n))';
+oo_.olsgibbs.(model_name).posterior.mean.h = mean(oo_.olsgibbs.(model_name).draws(:,n+1));
+oo_.olsgibbs.(model_name).posterior.variance.beta = cov(oo_.olsgibbs.(model_name).draws(:,1:n));
+oo_.olsgibbs.(model_name).posterior.variance.h = var(oo_.olsgibbs.(model_name).draws(:,n+1));
+oo_.olsgibbs.(model_name).s2 = mean(oo_.olsgibbs.(model_name).draws(:,n+2));
+oo_.olsgibbs.(model_name).R2 = mean(oo_.olsgibbs.(model_name).draws(:,n+3));
+
+% Yhat
+idx = 0;
+yhatname = [eqtag '_olsgibbs_FIT'];
+if ~isempty(fitted_names_dict)
+    idx = strcmp(fitted_names_dict(:,1), eqtag);
+    if any(idx)
+        yhatname = fitted_names_dict{idx, 2};
+    end
+end
+oo_.olsgibbs.(model_name).Yhat = dseries(X*oo_.olsgibbs.(model_name).posterior.mean.beta, fp, yhatname);
+oo_.olsgibbs.(model_name).YhatOrig = oo_.olsgibbs.(model_name).Yhat;
+oo_.olsgibbs.(model_name).Yobs = dseries(Y, fp, lhsname);
+
+% Residuals
+oo_.olsgibbs.(model_name).resid = Y - oo_.olsgibbs.(model_name).Yhat;
+
+% Apply correcting function for Yhat if it was passed
+oo_.olsgibbs.(model_name).Yhat = oo_.olsgibbs.(model_name).Yhat + lhssub{1};
+if any(idx) ...
+        && length(fitted_names_dict(idx, :)) == 3 ...
+        && ~isempty(fitted_names_dict{idx, 3})
+    oo_.olsgibbs.(model_name).Yhat = ...
+        feval(fitted_names_dict{idx, 3}, oo_.olsgibbs.(model_name).Yhat);
+end
+ds.(oo_.olsgibbs.(model_name).Yhat.name) = oo_.olsgibbs.(model_name).Yhat;
+
+% Compute and save posterior densities.
+for i=1:n
+    xx = oo_.olsgibbs.(model_name).draws(:,i);
+    nn = length(xx);
+    bandwidth = mh_optimal_bandwidth(xx, nn, 0, 'gaussian');
+    [x, f] = kernel_density_estimate(xx, 512, nn, bandwidth,'gaussian');
+    oo_.olsgibbs.(model_name).posterior.density.(pnames{i}) = [x, f];
+end
+
+% Update model's parameters with posterior mean.
+idxs = zeros(length(pnames), 1);
+for j = 1:length(pnames)
+    idxs(j) = find(strcmp(M_.param_names, pnames{j}));
+    M_.params(idxs(j)) = oo_.olsgibbs.(model_name).posterior.mean.beta(j);
+end
+oo_.olsgibbs.(model_name).pnames = pnames;
+
+% Write .inc file
+write_param_init_inc_file('olsgibbs', model_name, idxs, oo_.olsgibbs.(model_name).posterior.mean.beta);
+
+%% Print Output
+if ~options_.noprint
+    ttitle = ['Bayesian estimation (with Gibbs sampling) of equation ''' eqtag ''''];
+    preamble = {['Dependent Variable: ' lhsname{:}], ...
+                sprintf('No. Independent Variables: %d', size(X,2)), ...
+                sprintf('Observations: %d from %s to %s\n', size(X,1), fp.char, lp.char)};
+    afterward = {sprintf('s^2: %f', oo_.olsgibbs.(model_name).s2), sprintf('R^2: %f', oo_.olsgibbs.(model_name).R2)};
+    dyn_table(ttitle, preamble, afterward, pnames, {'Posterior mean', 'Posterior std.'}, 4, [oo_.olsgibbs.(model_name).posterior.mean.beta, sqrt(diag(oo_.olsgibbs.(model_name).posterior.variance.beta))]);
+end
+end
diff --git a/matlab/optimization/gauss_newton.m b/matlab/optimization/gauss_newton.m
new file mode 100644
index 0000000000000000000000000000000000000000..28b8ee62997b34f3841fbab015d998c3a80cecb8
--- /dev/null
+++ b/matlab/optimization/gauss_newton.m
@@ -0,0 +1,97 @@
+function [x, objectivevalue, errorflag] = gauss_newton(fun, x0)
+
+% Minimization of the sum of squared residuals with the Gauss-Newton algorithm.
+%
+% The objective is to minimize:
+%
+%        fun(x)'*fun(x)
+%
+% with respect to x.
+%
+% INPUTS:
+% - funres          [handle]   Function from Rᵖ to Rⁿ, which given parameters (x) return the residuals of a non linear equation.
+% - x0              [double]   1×p vector, initial guess.
+%
+% OUTPUTS:
+% - x               [double]   1×p vector, vector of parameters minimizing the sum of squared residuals.
+% - objectivevalue  [double]   scalar, optimal value of the objective.
+% - errorflag       [integer]  scalar, nonzero if algorithm did not converge.
+
+% Copyright (C) 2018 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/>.
+
+maxIter = 100;           % Maximum number of iteration.
+h = sqrt(eps(1.0));      % Pertubation size for numerical computation of the Jacobian matrix
+xtol = 1e-6;             % Stopping criterion.
+phi = .5*(sqrt(5)+1.0);  % Golden number.
+
+errorflag = 0;
+
+noconvergence = true;
+counter = 0;
+
+while noconvergence
+    % Compute residuals and descent direction
+    [r0, J] = jacobian(fun, x0, h);
+    d = pinv(J)*r0;
+    % Update parameters
+    x1 = x0+d;
+    % Test if the step actually reduce the sum of squared residuals.
+    r1 = fun(x1);
+    s0 = r0'*r0;
+    s1 = r1'*r1;
+    if s1>s0
+        % Gauss-Newton step increased the Sum of Squared Residuals...
+        % We search for another point in the same direction using Golden section search.
+        l1 = 0;
+        l2 = 1;
+        L1 = l2-(l2-l1)/phi;
+        L2 = l1+(l2-l1)/phi;
+        while abs(L1-L2)>1e-6
+            if ssr(x0+L1*d)<ssr(x0+L2*d)
+                l2 = L2;
+            else
+                l1 = L1;
+            end
+            L1 = l2-(l2-l1)/phi;
+            L2 = l1+(l2-l1)/phi;
+        end
+        scale = .5*(l1+l2);
+        x1 = x0+scale*d;
+    else
+        scale = 1.0;
+    end
+    noconvergence = max(abs(x1-x0))>xtol;
+    counter = counter+1;
+    x0 = x1;
+    if counter>maxIter
+        break
+    end
+end
+
+x = x0;
+objectivevalue = s1;
+
+errorflag = isequal(counter, maxIter+1);
+
+function s = ssr(x)
+    % Evaluate the sum of square residuals.
+    r = fun(x);
+    s = r'*r;
+end
+
+end
\ No newline at end of file
diff --git a/matlab/optimization/jacobian.m b/matlab/optimization/jacobian.m
new file mode 100644
index 0000000000000000000000000000000000000000..32f6adf32a7fecc2ed979e0eec70dbd98445f6a5
--- /dev/null
+++ b/matlab/optimization/jacobian.m
@@ -0,0 +1,26 @@
+function [r, J] = jacobian(fun, x, h)
+
+% Returns the Jacobian matrix associated to a function.
+%
+% INPUTS:
+% - fun    [handle]   Function from Rᵖ to Rⁿ.
+% - x      [double]   1×p vector, point where the Jacobian has to be evaluated.
+% - h      [double]   scalar, perturbation size.
+%
+% OUTPUTS:
+% - r      [double]   n×1 vector, value of the function at point x.
+% - J      [double]   n×p matrix of derivatives.
+
+r = fun(x);
+
+if nargout>1
+    z = x;
+    n = length(r);
+    p = length(x);
+    J = zeros(n, p);
+    for i=1:p
+        x = z;
+        x(i) = x(i)+h;
+        J(:,i) = (r-fun(x))/h;
+    end
+end
\ No newline at end of file
diff --git a/matlab/pac-tools/a2alpha.m b/matlab/pac-tools/a2alpha.m
new file mode 100644
index 0000000000000000000000000000000000000000..2e2b319378065e111ca5ba223ceb659efa910a34
--- /dev/null
+++ b/matlab/pac-tools/a2alpha.m
@@ -0,0 +1,56 @@
+function alpha = a2alpha(a)
+
+% Computes the m alpha coefficients from the m a coefficients of the PAC model.
+%
+% INPUTS 
+% - a      [double]   m*1 vector of coefficients.
+%
+% OUTPUTS 
+% - alpha  [double]   m*1 vector of coefficients.
+%
+% NOTES 
+%
+%  Given the current estimate of the PAC parameters a_0, a_1, ..., a_{m-1}, the routine does the following:
+%
+%  \alpha_{m} = a_{m-1}
+%  \alpha_{m-1} = a_{m-2}-a_{m-1}
+%  \alpha_{m-2} = a_{m-3}-a_{m-2}
+%  ...
+%  \alpha_3 = a_2-a_3
+%  \alpha_2 = a_1-a_2
+%  \alpha_1 = a_0-a_1-1
+%
+% Note that the last elements of input a are (a_0, a_1, ..., a_{m-1}).
+
+% Copyright (C) 2018 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/>.
+
+% Return an error if the input is not a vector
+if ~isvector(a)
+    error('Input argument has to be a vector of doubles!')
+end 
+
+% Get the number of PAC parameters (without the discount factor)
+m = length(a);
+
+% Initialize the vector of transformed PAC parameters.
+alpha = zeros(m, 1);
+
+% Compute the transformed parameters
+alpha(m) = a(m);
+alpha(2:m-1) = a(2:m-1)-a(3:m);
+alpha(1) = a(1)-a(2)-1;
\ No newline at end of file
diff --git a/matlab/pac-tools/buildGmatrix.m b/matlab/pac-tools/buildGmatrix.m
new file mode 100644
index 0000000000000000000000000000000000000000..6685aedfa5efb1e7516c2618ceb9c86aa610d48d
--- /dev/null
+++ b/matlab/pac-tools/buildGmatrix.m
@@ -0,0 +1,57 @@
+function G = buildGmatrix(alpha, beta)
+    
+% Builds the G matrix needed for PAC.
+%
+% INPUTS 
+% - alpha    [double]    m*1 vector of PAC parameters (lag polynomial parameters).
+% - beta     [double]    scalar, discount factor.
+%
+% OUTPUTS 
+% - G         [double]    (m+1)*(m+1) matrix.
+
+% Copyright (C) 2018 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/>.
+
+if nargin<2
+    error('Two input arguments are required (vector of alpha parameters and beta discount parameter)!')
+end
+
+% Return an error if the first input is not a real vector.
+if ~isnumeric(alpha) || ~isreal(alpha) || ~isvector(alpha)
+    error('First input argument has to be a vector of doubles!')
+end 
+
+% Return an error if the second input argument is not a discount factor
+if ~isnumeric(beta) || ~isreal(beta) || ~isscalar(beta) || beta<eps || beta>1-eps
+    error('Second input argument has to be a discount factor!')
+end 
+
+% Get the number of parameters
+m = length(alpha);
+
+% Return an error if params is too small.
+if m<1
+    error('First input argument has to be a vector with at least one element.')
+end
+
+% Initialize the returned G matrix.
+G = zeros(m);
+
+% Fill the returned G matrix.
+G(1:m-1,2:m) = eye(m-1);
+G(m, :) = -flip(transpose(alpha));
+G(m, :) = G(m, :).*flip(cumprod(beta*ones(1,m)));
\ No newline at end of file
diff --git a/matlab/pac-tools/buildGmatrixWithAlphaAndBeta.m b/matlab/pac-tools/buildGmatrixWithAlphaAndBeta.m
new file mode 100644
index 0000000000000000000000000000000000000000..1565bd5006b9eeb9b9849096028258974c614814
--- /dev/null
+++ b/matlab/pac-tools/buildGmatrixWithAlphaAndBeta.m
@@ -0,0 +1,58 @@
+function [G, alpha, beta] = buildGmatrixWithAlphaAndBeta(params)
+    
+% Builds the G matrix needed for PAC.
+%
+% INPUTS 
+% - params    [double]    (m+1)*1 vector of PAC parameters.
+%
+% OUTPUTS 
+% - G         [double]    (m+1)*(m+1) matrix.
+% - alpha     [double]    m*1 vector of PAC parameters.
+% - beta      [double]    scalar, discount factor.
+
+% Copyright (C) 2018 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/>.
+
+% Return an error if the input is not a vector.
+if ~isvector(params) || ~isnumeric(params) || ~isreal(params)
+    error('Input argument has to be a vector of doubles!')
+end 
+
+% Get the number of parameters
+m = length(params)-1;
+
+% Return an error if params is too small.
+if m<1
+    error('Input argument has to be a vector with at least two elements. The last element is the discount factor.')
+end
+
+% Get the transformed PAC parameters and discount factor.
+alpha = flip(a2alpha(params(1:m)));
+beta = params(end);
+
+% Return an error if beta is not a discount factor
+if beta<eps || beta>1-eps
+    error('beta has to be a discount factor!')
+end 
+
+% Initialize the returned G matrix.
+G = zeros(m);
+
+% Fill the returned G matrix.
+G(1:m-1,2:m) = eye(m-1);
+G(m, :) = -transpose(alpha);
+G(m, :) = G(m, :).*flip(cumprod(beta*ones(1,m)));
\ No newline at end of file
diff --git a/matlab/pac-tools/geteqtag.m b/matlab/pac-tools/geteqtag.m
new file mode 100644
index 0000000000000000000000000000000000000000..e9120480354eaed4fcd8882eb4d919cf6b3603de
--- /dev/null
+++ b/matlab/pac-tools/geteqtag.m
@@ -0,0 +1,30 @@
+function eqtag = geteqtag(eqname, pacname, Model)
+
+% Returns the equation tag, as defined by the preprocessor,
+% associated to a pac equation.
+%
+% INPUTS
+% - eqname     [char]    1×n array, name of the PAC equation.
+% - pacname    [char]    1×m array, name of the PAC model.
+%
+% OUTPUTS
+% - eqtag      [char]    equation tag associated to eqname.
+
+% Copyright © 2019 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/>.
+
+eqtag = Model.pac.(pacname).tag_map{strcmp(eqname, Model.pac.(pacname).tag_map(:,1)),2};
\ No newline at end of file
diff --git a/matlab/pac-tools/hVectors.m b/matlab/pac-tools/hVectors.m
new file mode 100644
index 0000000000000000000000000000000000000000..f057d7fa0aeabe3653079eef74aa59e5d36558c1
--- /dev/null
+++ b/matlab/pac-tools/hVectors.m
@@ -0,0 +1,75 @@
+function [h0, h1, longruncorrectionparameter] = hVectors(params, H, ids, idns, auxmodel)
+
+% INPUTS
+% - params          [double]     (m+1)*1 vector, PAC parameters (lag polynomial coefficients and discount factor).
+% - H               [double]     (np*np) matrix, companion matrix of the VAR(p) model.
+% - ids             [integer]    n*1 vector, selection of the stationary components of the VAR.
+% - idns            [integer]    n*1 vector, selection of the non stationary components of the VAR.
+%
+% OUTPUTS
+% - h0              [double]     1*n vector.
+% - h1              [double]     1*n vector.
+%
+% REMARKS
+% The parameters are ordered as follows in the params vector:
+%
+%    params(1)       ⟶ Error correction parameter.
+%    params(2:end-1) ⟶ Autoregressive parameters.
+%    params(end)     ⟶ Discount factor.
+
+% Copyright (C) 2018 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/>.
+
+if nargout>1 && nargin<4
+    error('Wrong number of Inputs/Outputs!')
+end
+
+[G, alpha, beta] = buildGmatrixWithAlphaAndBeta(params);
+
+A = [alpha; 1];
+
+A_1 = polyval(A, 1.0);
+A_b = polyval(A, beta);
+
+m = length(alpha);
+n = length(H);
+
+tmp = eye(n*m)-kron(G, transpose(H));
+
+if isempty(ids)
+    h0 = [];
+else
+    h0 = A_1*A_b*((kron(iota(m, m), H))'*(tmp\kron(iota(m, m), iota(n, ids))));
+end
+
+if nargout>1
+    if isempty(idns)
+        h1 = [];
+    else
+        switch auxmodel
+          case {'var', 'trend_component'}
+            h1 = A_1*A_b*(kron(iota(m, m)'*inv(eye(m)-G), H')*(tmp\kron(iota(m, m), iota(n, idns))));
+          case 'Need to check in which case we should trigger this one...'
+            h1 = A_1*A_b*(kron(iota(m, m)'*inv(eye(m)-G), (H'-eye(length(H))))*(tmp\kron(iota(m, m), iota(n, idns))));
+        end
+    end
+end
+
+if nargout>2
+    d = A_1*A_b*(iota(m, m)'*inv((eye(m)-G)*(eye(m)-G))*iota(m, m));
+    longruncorrectionparameter = (1-sum(params(2:end-1))-d);
+end
\ No newline at end of file
diff --git a/matlab/pac-tools/iota.m b/matlab/pac-tools/iota.m
new file mode 100644
index 0000000000000000000000000000000000000000..e7613f07294be8385cd6c4ebea0c9ed326378a32
--- /dev/null
+++ b/matlab/pac-tools/iota.m
@@ -0,0 +1,50 @@
+function i = iota(n, idx)
+
+% Returns a selection vector.
+%
+% INPUTS 
+% - n      [integer]   scalar, dimension of the returned vector.
+% - idx    [integer]   vector or scalar, non zero entries indices in the returned vector.
+%
+% OUTPUTS 
+% - i      [integer]   n*1 vector. All elements are zero except those specified in idx.
+
+% Copyright (C) 2018 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/>.
+
+if ~isscalar(n) || ~isvector(idx)
+    error('First input has to be a scalar and second input a vector!')
+end
+
+if (n-round(n))>eps(0) || any((idx-round(idx))>eps(0))
+    error('Inputs must have integer values!')
+end
+
+if n<1
+    error('First input argument must be a strictly positive integer!')
+end
+
+if any(idx>n)
+    error('Elements in second argument cannot be greater than the first argument!')
+end
+
+if any(idx<1)
+    error('Elements in the second argument must be positive!')
+end
+
+i = zeros(n, 1);
+i(idx) = 1;
\ No newline at end of file
diff --git a/matlab/perfect-foresight-models/make_ex_.m b/matlab/perfect-foresight-models/make_ex_.m
index a77488fc7b99fd2806c6a285ac18514497dd6ce6..3c8922f8062c8df3b36fc5481d4b901fa73c6cee 100644
--- a/matlab/perfect-foresight-models/make_ex_.m
+++ b/matlab/perfect-foresight-models/make_ex_.m
@@ -1,18 +1,14 @@
-function oo_=make_ex_(M_,options_,oo_)
-% forms oo_.exo_simul and oo_.exo_det_simul
+function oo_ = make_ex_(M_, options_, oo_)
+
+% Forms oo_.exo_simul and oo_.exo_det_simul
 %
 % INPUTS
-%   M_:           Dynare model structure
-%   options_:     Dynare options structure
-%   oo_:          Dynare results structure
+% - M_           [struct]   Dynare model structure
+% - options_     [struct]   Dynare options structure
+% - oo_          [struct]   Dynare results structure
 %
 % OUTPUTS
-%   oo_:          Dynare results structure
-%
-% ALGORITHM
-%
-% SPECIAL REQUIREMENTS
-%
+% - oo_          [struct]   Updated dynare results structure
 
 % Copyright (C) 1996-2020 Dynare Team
 %
diff --git a/matlab/perfect-foresight-models/make_y_.m b/matlab/perfect-foresight-models/make_y_.m
index 48cc0e58ab1ffb2c9ec5c2506d2dafff4e655753..585b69fe89488353db8b43b43a9afb748e2f4a4b 100644
--- a/matlab/perfect-foresight-models/make_y_.m
+++ b/matlab/perfect-foresight-models/make_y_.m
@@ -1,20 +1,14 @@
-function oo_=make_y_(M_,options_,oo_)
-% function oo_=make_y_(M_,options_,oo_)
+function oo_=make_y_(M_, options_, oo_)
+
 % forms oo_.endo_simul as guess values for deterministic simulations
 %
 % INPUTS
-%   M_:           Dynare model structure
-%   options_:     Dynare options structure
-%   oo_:          Dynare results structure
+% - M_          [struct]   Dynare model structure
+% - options_    [struct]   Dynare options structure
+% - oo_         [struct]   Dynare results structure
 %
 % OUTPUTS
-%   oo_:          Dynare results structure
-%
-% ALGORITHM
-%   ...
-% SPECIAL REQUIREMENTS
-%   none
-%
+% - oo_         [struct]   Updated dynare results structure
 
 % Copyright (C) 1996-2020 Dynare Team
 %
diff --git a/matlab/perfect-foresight-models/perfect_foresight_setup.m b/matlab/perfect-foresight-models/perfect_foresight_setup.m
index 98d8e12fc22f1f66b4cf9de8566865f9eb624466..9a8877e872cc79260e1ec114b3c20f81ed9840b8 100644
--- a/matlab/perfect-foresight-models/perfect_foresight_setup.m
+++ b/matlab/perfect-foresight-models/perfect_foresight_setup.m
@@ -65,5 +65,4 @@ if ~isempty(M_.det_shocks) && options_.periods<max([M_.det_shocks.periods])
 end
 
 oo_ = make_ex_(M_,options_,oo_);
-oo_ = make_y_(M_,options_,oo_);
-
+oo_ = make_y_(M_,options_,oo_);
\ No newline at end of file
diff --git a/matlab/plot_contributions.m b/matlab/plot_contributions.m
new file mode 100644
index 0000000000000000000000000000000000000000..9f22e21be08847885cf8e8fd7ac7ff3a021841f9
--- /dev/null
+++ b/matlab/plot_contributions.m
@@ -0,0 +1,202 @@
+function plot_contributions(equationname, ds1, ds0)
+%function plot_contributions(equationname, ds1, ds0)
+% Plots the contribution to the lhs variable of the rhs variables in an equation.
+%
+% INPUTS
+%  - equationname      [string]                 Name of an equation.
+%  - ds1               [string, dseries]        Object containing all the variables (exogenous and endogenous)
+%                                               appearing in the equation, or the name of the dseries object.
+%  - ds0               [string, dseries]        Object containing the baseline for all the variables (exogenous
+%                                               and endogenous) appearing in the equation, or the name of the
+%                                               dseries object.
+%
+% OUTPUTS
+%  none
+%
+% SPECIAL REQUIREMENTS
+%  The user must have attached names to the equations using equation
+%  tags. Each equation in the model block must be preceeded with a
+%  tag (see the reference manual). For instance, we should have
+%  something as:
+%
+%      [name='Phillips curve']
+%      pi = beta*pi(1) + slope*y + lam;
+
+% Copyright (C) 2017-2019 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/>.
+
+global M_
+
+jsonfile = [M_.fname filesep() 'model' filesep() 'json' filesep() 'modfile-original.json'];
+if exist(jsonfile, 'file') ~= 2
+    error('Could not find %s! Please use the json option (See the Dynare invocation section in the reference manual).', jsonfile);
+end
+
+% Check the number of input arguments.
+if nargin>3
+    error('plot_contributions:: Exactly three arguments are required!')
+end
+
+% Check the type of the first argument
+if ~ischar(equationname)
+    error('First argument must be a string.')
+end
+
+% Check that the equation name is actually the name of an equation in the model.
+if ~ismember(equationname, M_.equations_tags(strmatch('name', M_.equations_tags(:,2)),3))
+    error('There is no equation named as %s!', equationname);
+end
+
+% Check second argument
+if ischar(ds1)
+    if ismember(ds1, evalin('caller','who'))
+        ds = evalin('caller', ds1);
+        if isdseries(ds)
+            ds1 = copy(ds); clear ds;
+        else
+            error('plot_contributions:: %s is not a dseries object!', ds1)
+        end
+    else
+        error('plot_contributions:: %s is unknown!', ds1)
+    end
+else
+    if ~isdseries(ds1)
+        error('plot_contributions:: Second input argument must be a dseries object!')
+    end
+end
+
+% Check third argument
+if ischar(ds0)
+    if ismember(ds0, evalin('caller','who'))
+        ds = evalin('caller', ds0);
+        if isdseries(ds)
+            ds0 = copy(ds); clear ds;
+        else
+            error('plot_contributions:: %s is not a dseries object!', ds0)
+        end
+    else
+        error('plot_contributions:: %s is unknown!', ds0)
+    end
+else
+    if ~isdseries(ds0)
+        error('plot_contributions:: Third input argument must be a dseries object!')
+    end
+end
+
+% Get equation.
+[~, jsonmodel] = get_ast(equationname);
+lhs = jsonmodel{1}.lhs;
+rhs = jsonmodel{1}.rhs;
+
+% Get variable and parameter names in the equation.
+rhs_ = strsplit(rhs,{'+','-','*','/','^','log(','diff(','adl(','exp(','(',')'});
+rhs_(cellfun(@(x) all(isstrprop(x, 'digit')+isstrprop(x, 'punct')), rhs_)) = []; % Remove numbers
+pnames = M_.param_names;
+vnames = setdiff(rhs_, pnames);
+pnames = setdiff(rhs_, vnames);
+
+regexprnoleads = cell2mat(strcat('(', vnames, {'\(\d+\))|'}));
+if ~isempty(regexp(rhs, regexprnoleads(1:end-1), 'match'))
+    error(['plot_contributions: you cannot have leads in equation on line ' lineno ': ' lhs ' = ' rhs]);
+end
+
+% Get values for the parameters
+if ~isempty(pnames)
+    % In case all the parameters are hard coded
+    idp = strmatch(pnames{1}, M_.param_names, 'exact');
+    str = sprintf('%s = M_.params(%d);', pnames{1}, idp);
+    for i=2:length(pnames)
+        idp = strmatch(pnames{i}, M_.param_names, 'exact');
+        str = sprintf('%s %s = M_.params(%d);', str, pnames{i}, idp);
+    end
+    eval(str)
+end
+
+% Replace variables with ds.variablename
+for i = 1:length(vnames)
+    if ismember(vnames{i}, ds1.name) && ismember(vnames{i}, ds0.name)
+        % Match all words with vnames{i}
+        [b, e] = regexp(rhs, sprintf('\\w*%s\\w*', vnames{i}));
+        % Filter out non exact matches (words longer than vnames{i})
+        rid = find(~(e-b>=length(vnames{i})));
+        if ~isempty(rid)
+            b = b(rid);
+            e = e(rid);
+        end
+        % Substitute vnames{i} exact matches by ds.vnames{i}
+        for j=length(rid):-1:1
+            if b(j)>1 && e(j)<length(rhs)
+                rhs = sprintf('%sds.%s%s', rhs(1:b(j)-1), vnames{i}, rhs(e(j)+1:end));
+            elseif isequal(b(j), 1)
+                rhs = sprintf('ds.%s%s', vnames{i}, rhs(e(j)+1:end));
+            elseif isequal(e(j), length(rhs))
+                rhs = sprintf('%sds.%s', rhs(1:b(j)-1), vnames{i});
+            end
+        end
+    else
+        if ismember(vnames{i}, ds1.name)
+            error('Variable %s is not available in the second dseries (baseline paths)!', vnames{i})
+        else
+            error('Variable %s is not available in the first dseries (actual paths)!', vnames{i})
+        end
+    end
+end
+
+% Initialize an array for the contributions.
+contribution = zeros(ds1.nobs, ds1.vobs + 1);
+
+% Evaluate RHS with all the actual paths.
+ds = ds1;
+rhseval = eval(rhs);
+ds = ds0;
+rhseval_other = eval(rhs);
+contribution(:, 1) = rhseval.data - rhseval_other.data;
+
+% Evaluate RHS with the baseline paths.
+ds = ds0;
+rhs0 = eval(rhs);
+
+% Compute the marginal effect of each variable on the RHS, by evaluating the
+% RHS with all variables at the Baseline paths except one for which the
+% actual path is used.
+for i = 1:length(vnames)
+    ds = ds0; % Set all variable to Baseline paths.
+    ds{vnames{i}} = ds1{vnames{i}};
+    rhsval = eval(rhs)-rhs0;
+    contribution(:, i+1) = rhsval.data;
+end
+
+% Create the contributions plot.
+figure('Name', lhs);
+hold on
+cc = contribution(:,2:end);
+
+% Limit the matrices to what we care about
+ccneg = cc(:,1:length(vnames)); ccneg(ccneg>=0) = nan;
+ccpos = cc(:,1:length(vnames)); ccpos(ccpos<0) = nan;
+H = bar(1:ds.nobs, ccneg, 'stacked');
+set(gca,'ColorOrderIndex',1);
+B = bar(1:ds.nobs, ccpos, 'stacked');
+line_ = plot(1:ds.nobs, contribution(:,1), '-r', 'linewidth', 2);
+hold off
+
+lhs = strrep(lhs, '_', '\_');
+title(sprintf('Decomposition of %s', lhs))
+
+vnames = strrep(vnames,'_','\_');
+legend([H, line_], [vnames, lhs], 'location', 'northwest');
+
diff --git a/matlab/print_equations.m b/matlab/print_equations.m
new file mode 100644
index 0000000000000000000000000000000000000000..256c110fefbcae6b37bb1ca85cdfd96b2ff75768
--- /dev/null
+++ b/matlab/print_equations.m
@@ -0,0 +1,93 @@
+function print_equations(variable_name, withexpansion)
+
+% Prints equations where the variable appears in.
+%
+% INPUTS
+% - variable_name       [string]    Name of the variable to be traced.
+% - withexpansion       [logical]   Prints expanded equation of the VAR_EXPECTATION or PAC_EXPECTATION term if true.
+%
+% OUTPUTS
+% None
+
+% Copyright (C) 2019 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/>.
+
+global M_
+
+if nargin == 0
+    error('Provide variable name as input argument.');
+elseif nargin == 1
+    % Assign default value for VAR_EXPECTATION/PAC_EXPECTATION expression expansion.
+    withexpansion = false;
+elseif nargin == 2
+    if ~islogical(withexpansion)
+        error('Second input argument must be Boolean.');
+    end
+end
+
+% Check if corresponding JSON file exists.
+fname = [M_.fname filesep 'model' filesep 'json' filesep 'modfile-original.json'];
+if exist(fname, 'file') ~= 2
+    error('Could not find %s! Please use the json option (See the Dynare invocation section in the reference manual).', fname);
+end
+
+% Check that the first input is a character array.
+if ~ischar(variable_name)
+    error('First input argument must be a string.');
+end
+    
+% Check that the variable is actually a variable in the model.
+if ~ismember(variable_name, [M_.exo_names; M_.endo_names])
+    error('There is no variable named %s!', variable_name);
+end
+
+% Load the JSON file.
+jsonfile = loadjson_(fname);
+model = jsonfile.model;
+
+% Print the equations the variable appears in.
+for it = 1:length(M_.mapping.(variable_name).eqidx)
+    rhs = model{M_.mapping.(variable_name).eqidx(it)}.rhs;
+    if withexpansion
+        if isfield(M_, 'pac') && contains(rhs, 'pac_expectation')
+            % Get the index of the equation's PAC model.
+            models = fieldnames(M_.pac);
+            idx = find(~cellfun('isempty',cellfun(@(s)find(contains(rhs,s)),models,'uni',0)));
+            % Get the expanded PAC_EXPECTATION term.
+            [pac_expression, growthneutralitycorrection] = write_expectations(M_.pac.(models{idx}).tag_map(:,1), models{idx}, 'pac', true);
+            expression = [sprintf('\n\t + %s', growthneutralitycorrection) TransformExpandedExpr(pac_expression)];
+            rhs = strrep(rhs, ['+pac_expectation(model_name = ' models{idx} ')'], expression);
+        elseif isfield(M_, 'var_expectation') && contains(rhs, 'var_expectation')
+            % Get the index of the equation's VAR model.
+            models = fieldnames(M_.var_expectation);
+            idx = find(~cellfun('isempty',cellfun(@(s)find(contains(rhs,s)),models,'uni',0)));
+            % Get the expanded VAR_EXPECTATION term.
+            expression = write_expectations('fake', models{idx}, 'var', true);
+            expression = TransformExpandedExpr(expression);
+            rhs = strrep(rhs, ['+var_expectation(model_name = ' models{idx} ')'], expression);
+        elseif ~isfield(M_, 'pac') && ~isfield(M_, 'var_expectation')
+            warning('No VAR or PAC expectations found, continuing without expansion');
+            withexpansion = false;
+        end
+    end
+    fprintf('%s = %s;\n', model{M_.mapping.(variable_name).eqidx(it)}.lhs, rhs);
+end
+
+function [transformed_expression] = TransformExpandedExpr(expression)
+    transformed_expression = splitlines(expression);
+    transformed_expression{1} = sprintf(' + %s', transformed_expression{1});
+    transformed_expression = sprintf('\n\t%s', transformed_expression{:});
\ No newline at end of file
diff --git a/matlab/print_expectations.m b/matlab/print_expectations.m
new file mode 100644
index 0000000000000000000000000000000000000000..f0a4b42980216cd98ff4a3eee5fe48fbee292254
--- /dev/null
+++ b/matlab/print_expectations.m
@@ -0,0 +1,369 @@
+function print_expectations(eqname, expectationmodelname, expectationmodelkind, withcalibration)
+
+% Prints the exansion of the VAR_EXPECTATION or PAC_EXPECTATION term in files.
+%
+% INPUTS
+% - eqname                      [string]    Name of the equation.
+% - epxpectationmodelname       [string]    Name of the expectation model.
+% - expectationmodelkind        [string]    Kind of the expectation model.
+% - withcalibration             [logical]   Prints calibration if true.
+%
+% OUTPUTS
+% None
+%
+% REMARKS
+% The routine creates two text files
+%
+% - {expectationmodelname}-parameters.inc     which contains the declaration of the parameters specific to the expectation model kind term.
+% - {expectationmodelname}-expression.inc     which contains the expanded version of the expectation model kind term.
+%
+% These routines are saved under the {modfilename}/model/{expectationmodelkind} subfolder, and can be
+% used after in another mod file (ie included with the macro directive @#include).
+%
+% The variable expectationmodelkind can take two values 'var' or 'pac'.
+
+% Copyright (C) 2018-2019 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/>.
+
+global M_
+
+if nargin<4 || isempty(withcalibration)
+    withcalibration = true;
+end
+
+% Check that the first input is a row character array.
+if ~isrow(eqname)==1 || ~ischar(eqname)
+    error('First input argument must be a row character array.')
+end
+
+% Check that the second input is a row character array.
+if ~isrow(expectationmodelname)==1 || ~ischar(expectationmodelname)
+    error('Second input argument must be a row character array.')
+end
+
+% Check that the third input is a row character array.
+if ~isrow(expectationmodelkind)==1 || ~ischar(expectationmodelkind)
+    error('Third input argument must be a row character array.')
+end
+
+% Check that the value of the second input is correct.
+if ~ismember(expectationmodelkind, {'var', 'pac'})
+    error('Wrong value for the second input argument.')
+end
+
+% Check that the model exists.
+switch expectationmodelkind
+  case 'var'
+    if ~isfield(M_.var_expectation, expectationmodelname)
+        error('VAR_EXPECTATION_MODEL %s is not defined.', expectationmodelname)
+    else
+        expectationmodelfield = 'var_expectation';
+    end
+  case 'pac'
+    if ~isfield(M_.pac, expectationmodelname)
+        error('PAC_EXPECTATION_MODEL %s is not defined.', expectationmodelname)
+    else
+        expectationmodelfield = 'pac';
+    end
+  otherwise
+end
+
+if isequal(expectationmodelkind, 'pac')
+    % Get the equation tag (in M_.pac.(pacmodl).equations)
+    eqtag = M_.pac.(expectationmodelname).tag_map{strcmp(M_.pac.(expectationmodelname).tag_map(:,1), eqname),2};
+end
+
+% Get the expectation model description
+expectationmodel = M_.(expectationmodelfield).(expectationmodelname);
+
+% Get the name of the associated VAR model and test its existence.
+if ~isfield(M_.(expectationmodel.auxiliary_model_type), expectationmodel.auxiliary_model_name)
+    switch expectationmodelkind
+      case 'var'
+        error('Unknown VAR/TREND_COMPONENT model (%s) in VAR_EXPECTATION_MODEL (%s)!', expectationmodel.auxiliary_model_name, expectationmodelname)
+      case 'pac'
+        error('Unknown VAR/TREND_COMPONENT model (%s) in PAC_EXPECTATION_MODEL (%s)!', expectationmodel.auxiliary_model_name, expectationmodelname)
+      otherwise
+    end
+end
+
+auxmodel = M_.(expectationmodel.auxiliary_model_type).(expectationmodel.auxiliary_model_name);
+
+%
+% First print the list of parameters appearing in the VAR_EXPECTATION/PAC_EXPECTATION term.
+%
+if ~exist(sprintf('%s/model/%s', M_.fname, [expectationmodelkind '-expectations']), 'dir')
+    mkdir(sprintf('%s/model/%s', M_.fname, [expectationmodelkind '-expectations']))
+end
+
+if isequal(expectationmodelkind, 'pac')
+    filename = sprintf('%s/model/%s/%s-%s-parameters.inc', M_.fname, [expectationmodelkind '-expectations'], eqtag, expectationmodelname);
+else
+    filename = sprintf('%s/model/%s/%s-parameters.inc', M_.fname, [expectationmodelkind '-expectations'], expectationmodelname);
+end
+fid = fopen(filename, 'w');
+fprintf(fid, '// This file has been generated by dynare (%s).\n\n', datestr(now));
+
+switch expectationmodelkind
+  case 'var'
+    parameter_declaration = 'parameters';
+    for i=1:length(expectationmodel.param_indices)
+        parameter_declaration = sprintf('%s %s', parameter_declaration, M_.param_names{expectationmodel.param_indices(i)});
+    end
+    fprintf(fid, '%s;\n\n', parameter_declaration);
+    if withcalibration
+        for i=1:length(expectationmodel.param_indices)
+            fprintf(fid, '%s = %1.16f;\n', M_.param_names{expectationmodel.param_indices(i)}, M_.params(expectationmodel.param_indices(i)));
+        end
+    end
+  case 'pac'
+    if ~isempty(expectationmodel.equations.(eqtag).h0_param_indices)
+        parameter_declaration = 'parameters';
+        for i=1:length(expectationmodel.equations.(eqtag).h0_param_indices)
+            parameter_declaration = sprintf('%s %s', parameter_declaration, M_.param_names{expectationmodel.equations.(eqtag).h0_param_indices(i)});
+        end
+        fprintf(fid, '%s;\n\n', parameter_declaration);
+        if withcalibration
+            for i=1:length(expectationmodel.equations.(eqtag).h0_param_indices)
+                fprintf(fid, '%s = %1.16f;\n', M_.param_names{expectationmodel.equations.(eqtag).h0_param_indices(i)}, M_.params(expectationmodel.equations.(eqtag).h0_param_indices(i)));
+            end
+        end
+    end
+    if ~isempty(expectationmodel.equations.(eqtag).h1_param_indices)
+        parameter_declaration = 'parameters';
+        for i=1:length(expectationmodel.equations.(eqtag).h1_param_indices)
+            parameter_declaration = sprintf('%s %s', parameter_declaration, M_.param_names{expectationmodel.equations.(eqtag).h1_param_indices(i)});
+        end
+        fprintf(fid, '%s;\n\n', parameter_declaration);
+        if withcalibration
+            for i=1:length(expectationmodel.equations.(eqtag).h1_param_indices)
+                fprintf(fid, '%s = %1.16f;\n', M_.param_names{expectationmodel.equations.(eqtag).h1_param_indices(i)}, M_.params(expectationmodel.equations.(eqtag).h1_param_indices(i)));
+            end
+        end
+    end
+    if isfield(expectationmodel, 'growth_neutrality_param_index')
+        fprintf(fid, '\n');
+        fprintf(fid, 'parameters %s;\n\n', M_.param_names{expectationmodel.growth_neutrality_param_index});
+        if withcalibration
+            fprintf(fid, '%s = %1.16f;\n', M_.param_names{expectationmodel.growth_neutrality_param_index}, M_.params(expectationmodel.growth_neutrality_param_index));
+        end
+        growth_correction = true;
+    else
+        growth_correction = false;
+    end
+  otherwise
+end
+
+fclose(fid);
+
+skipline()
+fprintf('Parameters declarations and calibrations are saved in %s.\n', filename);
+
+%
+% Second print the expanded VAR_EXPECTATION/PAC_EXPECTATION term.
+%
+
+if isequal(expectationmodelkind, 'pac')
+    filename = sprintf('%s/model/%s/%s-%s-expression.inc', M_.fname, [expectationmodelkind '-expectations'], eqtag, expectationmodelname);
+else
+    filename = sprintf('%s/model/%s/%s-expression.inc', M_.fname, [expectationmodelkind '-expectations'], expectationmodelname);
+end
+fid = fopen(filename, 'w');
+fprintf(fid, '// This file has been generated by dynare (%s).\n', datestr(now));
+
+switch expectationmodelkind
+  case 'var'
+    expression = write_expectations(eqname, expectationmodelname, expectationmodelkind, true);
+  case 'pac'
+    [expression, growthneutralitycorrection] = write_expectations(eqname, expectationmodelname, expectationmodelkind, true);
+end
+
+fprintf(fid, '%s', expression);
+fclose(fid);
+
+fprintf('Expectation unrolled expression is saved in %s.\n', filename);
+
+%
+% Second bis print the PAC growth neutrality correction term (if any).
+%
+
+if isequal(expectationmodelkind, 'pac') && growth_correction
+    filename = sprintf('%s/model/%s/%s-%s-growth-neutrality-correction.inc', M_.fname, [expectationmodelkind '-expectations'], eqtag, expectationmodelname);
+    fid = fopen(filename, 'w');
+    fprintf(fid, '// This file has been generated by dynare (%s).\n', datestr(now));
+    fprintf(fid, '%s', growthneutralitycorrection);
+    fclose(fid);
+    fprintf('Growth neutrality correction is saved in %s.\n', filename);
+end
+
+%
+% Third print a routine for evaluating VAR_EXPECTATION/PAC_EXPECTATION term (returns a dseries object).
+%
+kind = [expectationmodelkind '_expectations'];
+mkdir(sprintf('+%s/+%s/+%s', M_.fname, kind, expectationmodelname));
+if isequal(expectationmodelkind, 'pac')
+    filename = sprintf('+%s/+%s/+%s/%s_evaluate.m', M_.fname, kind, expectationmodelname, eqtag);
+else
+    filename = sprintf('+%s/+%s/+%s/evaluate.m', M_.fname, kind, expectationmodelname);
+end
+fid = fopen(filename, 'w');
+if isequal(expectationmodelkind, 'pac')
+    fprintf(fid, 'function ds = %s_evaluate(dbase)\n\n', eqtag);
+else
+    fprintf(fid, 'function ds = evaluate(dbase)\n\n');
+end
+if isequal(expectationmodelkind, 'pac')
+    fprintf(fid, '%% Evaluates %s term (%s in %s).\n', kind, expectationmodelname, eqname);
+else
+    fprintf(fid, '%% Evaluates %s term (%s).\n', kind, expectationmodelname);
+end
+fprintf(fid, '%%\n');
+fprintf(fid, '%% INPUTS\n');
+fprintf(fid, '%% - dbase     [dseries]  databse containing all the variables appearing in the auxiliary model for the expectation.\n');
+fprintf(fid, '%%\n');
+fprintf(fid, '%% OUTPUTS\n');
+fprintf(fid, '%% - ds        [dseries]  the expectation term .\n');
+fprintf(fid, '%%\n');
+fprintf(fid, '%% REMARKS\n');
+fprintf(fid, '%% The name of the appended variable in dbase is the declared name for the (PAC/VAR) expectation model.\n\n');
+fprintf(fid, '%% This file has been generated by dynare (%s).\n\n', datestr(now));
+fprintf(fid, 'ds = dseries();\n\n');
+
+id = 0;
+
+maxlag = max(auxmodel.max_lag);
+if isequal(expectationmodel.auxiliary_model_type, 'trend_component')
+    % Need to add a lag since the error correction equations are rewritten in levels.
+    maxlag = maxlag+1;
+end
+
+for i=1:maxlag
+    for j=1:length(auxmodel.list_of_variables_in_companion_var)
+        id = id+1;
+        variable = auxmodel.list_of_variables_in_companion_var{j};
+        transformations = {};
+        ida = get_aux_variable_id(variable);
+        op = 0;
+        while ida
+            op = op+1;
+            if isequal(M_.aux_vars(ida).type, 8)
+                transformations(op) = {'diff'};
+                variable = M_.endo_names{M_.aux_vars(ida).orig_index};
+                ida = get_aux_variable_id(variable);
+            elseif isequal(M_.aux_vars(ida).type, 10)
+                transformations(op) = {M_.aux_vars(ida).unary_op};
+                variable = M_.endo_names{M_.aux_vars(ida).orig_index};
+                ida = get_aux_variable_id(variable);
+            else
+                error('This case is not implemented.')
+            end
+        end
+        switch expectationmodelkind
+          case 'var'
+            parameter = M_.params(expectationmodel.param_indices(id));
+          case 'pac'
+            parameter = 0;
+            if ~isempty(expectationmodel.equations.(eqtag).h0_param_indices)
+                parameter = M_.params(expectationmodel.equations.(eqtag).h0_param_indices(id));
+            end
+            if ~isempty(expectationmodel.equations.(eqtag).h1_param_indices)
+                if ~parameter
+                    parameter = M_.params(expectationmodel.equations.(eqtag).h1_param_indices(id));
+                else
+                    parameter = parameter+M_.params(expectationmodel.equations.(eqtag).h1_param_indices(id));
+                end
+            end
+          otherwise
+        end
+        switch expectationmodelkind
+          case 'var'
+            if i>1
+                variable = sprintf('dbase.%s(-%d)', variable, i-1);
+            else
+                variable = sprintf('dbase.%s', variable);
+            end
+          case 'pac'
+            variable = sprintf('dbase.%s(-%d)', variable, i);
+          otherwise
+        end
+        if ~isempty(transformations)
+            for k=length(transformations):-1:1
+                variable = sprintf('%s.%s()', variable, transformations{k});
+            end
+        end
+        if isequal(id, 1)
+            if isequal(expectationmodelkind, 'pac') && growth_correction
+                pgrowth = M_.params(expectationmodel.growth_neutrality_param_index);
+                linearCombination = '';
+                for iter = 1:numel(expectationmodel.growth_linear_comb)
+                    vgrowth='';
+                    if expectationmodel.growth_linear_comb(iter).exo_id > 0
+                        vgrowth = strcat('dbase.', M_.exo_names{expectationmodel.growth_linear_comb(iter).exo_id});
+                    elseif expectationmodel.growth_linear_comb(iter).endo_id > 0
+                        vgrowth = strcat('dbase.', M_.endo_names{expectationmodel.growth_linear_comb(iter).endo_id});
+                    end
+                    if expectationmodel.growth_linear_comb(iter).lag ~= 0
+                        vgrowth = sprintf('%s(%d)', vgrowth, expectationmodel.growth_linear_comb(iter).lag);
+                    end
+                    if expectationmodel.growth_linear_comb(iter).param_id > 0
+                        if ~isempty(vgrowth)
+                            vgrowth = sprintf('%1.16f*%s',M_.params(expectationmodel.growth_linear_comb(iter).param_id), vgrowth);
+                        else
+                            vgrowth = num2str(M_.params(expectationmodel.growth_linear_comb(iter).param_id), '%1.16f');
+                        end
+                    end
+                    if abs(expectationmodel.growth_linear_comb(iter).constant) ~= 1
+                        if ~isempty(vgrowth)
+                            vgrowth = sprintf('%1.16f*%s', expectationmodel.growth_linear_comb(iter).constant, vgrowth);
+                        else
+                            vgrowth = num2str(expectationmodel.growth_linear_comb(iter).constant, '%1.16f');
+                        end
+                    end
+                    if iter > 1
+                        if expectationmodel.growth_linear_comb(iter).constant > 0
+                            linearCombination = sprintf('%s+%s', linearCombination, vgrowth);
+                        else
+                            linearCombination = sprintf('%s-%s', linearCombination, vgrowth);
+                        end
+                    else
+                        linearCombination=vgrowth;
+                    end
+                end
+                if parameter >= 0
+                    expression = sprintf('%1.16f*(%s)+%1.16f*%s', pgrowth, linearCombination, parameter, variable);
+                else
+                    expression = sprintf('%1.16f*(%s)-%1.16f*%s', pgrowth, linearCombination, -parameter, variable);
+                end
+            else
+                expression = sprintf('%1.16f*%s', parameter, variable);
+            end
+        else
+            if parameter>=0
+                expression = sprintf('%s+%1.16f*%s', expression, parameter, variable);
+            else
+                expression = sprintf('%s-%1.16f*%s', expression, -parameter, variable);
+            end
+        end
+    end
+end
+
+fprintf(fid, 'ds.%s = %s;', expectationmodelname, expression);
+fclose(fid);
+
+fprintf('Expectation dseries expression is saved in %s.\n', filename);
+
+skipline();
diff --git a/matlab/set_exogenous_variables_for_simulation.m b/matlab/set_exogenous_variables_for_simulation.m
new file mode 100644
index 0000000000000000000000000000000000000000..4b06580b254729fe6352b415116a086c2914a6bf
--- /dev/null
+++ b/matlab/set_exogenous_variables_for_simulation.m
@@ -0,0 +1,35 @@
+function DynareModel = set_exogenous_variables_for_simulation(DynareModel)
+
+% Appends the list of observed exogenous variables in Dynare's model structure (if any).
+%
+% INPUTS
+% - DynareModel   [struct]    Dynare's model global structure, M_.
+%
+% OUTPUTS
+% - DynareModel   [struct]    Dynare's model global structure, M_.
+%
+% SPECIAL REQUIREMENTS
+%    none
+
+% Copyright (C) 2019 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/>.
+
+if isfield(DynareModel, 'exo_partitions')
+    if isfield(DynareModel.exo_partitions, 'used')
+        DynareModel.simulation_exo_names = DynareModel.exo_names(~strcmpi('estimationonly', DynareModel.exo_partitions.used));
+    end
+end
\ No newline at end of file
diff --git a/matlab/set_observed_exogenous_variables.m b/matlab/set_observed_exogenous_variables.m
new file mode 100644
index 0000000000000000000000000000000000000000..c9e350f78d585560c6cb0e543a5ae4a11a8fecc5
--- /dev/null
+++ b/matlab/set_observed_exogenous_variables.m
@@ -0,0 +1,35 @@
+function DynareModel = set_observed_exogenous_variables(DynareModel)
+
+% Appends the list of observed exogenous variables in Dynare's model structure (if any).
+%
+% INPUTS
+% - DynareModel   [struct]    Dynare's model global structure, M_.
+%
+% OUTPUTS
+% - DynareModel   [struct]    Dynare's model global structure, M_.
+%
+% SPECIAL REQUIREMENTS
+%    none
+
+% Copyright (C) 2019 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/>.
+
+if isfield(DynareModel, 'exo_partitions')
+    if isfield(DynareModel.exo_partitions, 'status')
+        DynareModel.observed_exo_names = DynareModel.exo_names(strcmpi('observed', DynareModel.exo_partitions.status));
+    end
+end
\ No newline at end of file
diff --git a/matlab/setup_solvers.m b/matlab/setup_solvers.m
new file mode 100644
index 0000000000000000000000000000000000000000..71b49167b465e7f8bfa812f0e047bcfdd1b38faf
--- /dev/null
+++ b/matlab/setup_solvers.m
@@ -0,0 +1,97 @@
+function Model = setup_solvers(Model)
+
+% Setup solve_algo={12,14} by identifying equations with a log on the left hand side.
+%
+% INPUTS
+% - Model     [struct]      Model description, aka M_.
+% - Options   [struct]      Dynare's options, aka options_.
+%
+% OUTPUTS
+% - Model     [struct]      Updated model description.
+
+% Copyright © 2020 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/>.
+
+cannot_use_solve_algo_12_14 = false;
+
+try
+    json = loadjson_(sprintf('%s/model/json/modfile.json', Model.fname));
+catch
+    cannot_use_solve_algo_12_14 = true;
+    message = 'Algorithms solve_algo={12,14} require json output of the model (use json=compute option)';
+end
+
+if ~cannot_use_solve_algo_12_14
+
+    lhs = cell(length(json.model),1);
+    isauxdiffloggedrhs = false(length(json.model), 1);
+
+    for i = 1:length(json.model)
+        if length(json.model)>1
+            lhs{i} = json.model{i}.lhs;
+        else
+            lhs{i} = json.model.lhs;
+        end
+        if isempty(regexp(lhs{i}, '^\w+$|^log\(\w+\)$'))
+            cannot_use_solve_algo_12_14 = true;
+            message = sprintf('With solve_algo={12,14}, each equation must have on the left hand side a single variable or logged variable (equation %d does not satisfy this condition).', i);
+            break
+        end
+        if length(json.model)>1
+            rhs = json.model{i}.rhs;
+        else
+            rhs = json.model.lhs;
+        end
+        if i>Model.orig_endo_nbr &&  ~isempty(regexp(lhs{i}, '\<AUX_DIFF_(\d*)\>', 'once')) && ismember(lhs{i}, lhs(1:i-1)) && ...
+                ~isempty(regexp(rhs, 'log\(\w*\)-log\(\w*\(-1\)\)', 'once'))
+            isauxdiffloggedrhs(i) = true;
+        end
+    end
+
+end
+
+if ~cannot_use_solve_algo_12_14
+
+    islog = @(x) ~isempty(regexp(x, 'log\(\w*\)', 'once'));
+    
+    lhs0 = lhs;
+    for i=1:length(json.model)
+        if islog(lhs{i})
+            lhs0{i} = strrep(strrep(lhs{i}, 'log(', ''), ')', '');
+        end
+    end
+    
+    if ~isequal(length(unique(lhs0(1:Model.orig_endo_nbr))), length(lhs0(1:Model.orig_endo_nbr)))
+        cannot_use_solve_algo_12_14 = true;
+        message = sprintf('With solve_algo={12,14}, each equation must determine a different endogenous variable.')
+    end
+
+end
+
+if cannot_use_solve_algo_12_14
+    Model.isloggedlhs = {};
+    Model.lhs = {};
+    Model.isauxdiffloggedrhs = [];
+    Model.possible_to_use_solve_algo_12_14 = false;
+    Model.message_solve_algo_12_14 = message;
+else
+    Model.isloggedlhs = cellfun(islog, lhs);
+    Model.lhs = lhs;
+    Model.isauxdiffloggedrhs = isauxdiffloggedrhs;
+    Model.possible_to_use_solve_algo_12_14 = true;
+    Model.message_solve_algo_12_14 = '';
+end
\ No newline at end of file
diff --git a/matlab/steady_.m b/matlab/steady_.m
index 08890ee61eee3eebf47b26246bcaf7476832ce95..1e7096ef26d4e374d80a2c19c23a3966a5fdf30c 100644
--- a/matlab/steady_.m
+++ b/matlab/steady_.m
@@ -35,8 +35,8 @@ function [steady_state,params,info] = steady_(M_,options_,oo_)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
 
-if options_.solve_algo < 0 || options_.solve_algo > 12
-    error('STEADY: solve_algo must be between 0 and 12')
+if options_.solve_algo < 0 || options_.solve_algo > 14
+    error('STEADY: solve_algo must be between 0 and 14')
 end
 
 if ~options_.bytecode && ~options_.block && options_.solve_algo > 4 && ...
diff --git a/matlab/surgibbs.m b/matlab/surgibbs.m
new file mode 100644
index 0000000000000000000000000000000000000000..f9b1eecc9f6cb8dfe24b96dfbbd841c0ced1faf8
--- /dev/null
+++ b/matlab/surgibbs.m
@@ -0,0 +1,235 @@
+function ds = surgibbs(ds, param_names, beta0, A, ndraws, discarddraws, thin, eqtags, model_name)
+
+% Implements Gibbs Samipling for SUR
+%
+% INPUTS
+%   ds           [dseries]    data
+%   param_names  [cellstr]    list of parameters to estimate
+%   beta0        [vector]     prior values (in order of param_names)
+%   A            [matrix]     prior distribution variance (in order of
+%                             param_names)
+%   ndraws       [int]        number of draws
+%   discarddraws [int]        number of draws to discard
+%   thin         [int]        if thin == N, save every Nth draw
+%   eqtags       [cellstr]    names of equation tags to estimate. If empty,
+%                             estimate all equations
+%   model_name   [string]     name to use in oo_ and inc file
+%
+% OUTPUTS
+%   none
+%
+% SPECIAL REQUIREMENTS
+%   dynare must have been run with the option: json=compute
+%
+% REFERENCES
+% - Ando, Tomohiro and Zellner, Arnold. 2010. Hierarchical Bayesian Analysis of the
+%   Seemingly Unrelated Regression and Simultaneous Equations Models Using a
+%   Combination of Direct Monte Carlo and Importance Sampling Techniques.
+%   Bayesian Analysis Volume 5, Number 1, pp. 65-96.
+
+% Copyright (C) 2017-2020 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/>.
+
+global M_ oo_ options_
+
+%
+% Check inputs
+%
+
+assert(nargin >= 5 && nargin <= 9, 'Incorrect number of arguments passed to surgibbs');
+assert(isdseries(ds), 'The 1st argument must be a dseries');
+assert(iscellstr(param_names), 'The 2nd argument must be a cellstr');
+assert(isvector(beta0) && length(beta0) == length(param_names), ...
+    'The 3rd argument must be a vector with the same length as param_names and the same ');
+if isrow(beta0)
+    beta0 = beta0';
+end
+assert(ismatrix(A) && all(all((A == A'))) && length(beta0) == size(A, 2), ...
+    'The 4th argument must be a symmetric matrix with the same dimension as beta0');
+assert(isint(ndraws), 'The 5th argument must be an integer');
+if nargin == 5
+    discarddraws = 0;
+else
+    assert(isint(discarddraws), 'The 6th argument, if provided, must be an integer');
+end
+if nargin == 6
+    thin = 1;
+else
+    assert(isint(thin), 'The 7th argument, if provided, must be an integer');
+end
+
+if nargin <= 8
+    if ~isfield(oo_, 'surgibbs')
+        model_name = 'surgibbs_model_number_1';
+    else
+        model_name = ['surgibbs_model_number_' num2str(length(fieldnames(oo_.surgibbs)) + 1)];
+    end
+else
+    if ~isvarname(model_name)
+        error('The 9th argument must be a valid string');
+    end
+end
+
+%
+% Estimation
+%
+
+if nargin == 8
+    [nobs, X, Y, m, lhssub, fp] = sur(ds, param_names, eqtags);
+else
+    [nobs, X, Y, m, lhssub, fp] = sur(ds, param_names);
+end
+
+oo_.surgibbs.(model_name).dof = nobs;
+
+beta = beta0;
+A = inv(A);
+thinidx = 1;
+drawidx = 1;
+nparams = length(param_names);
+oo_.surgibbs.(model_name).betadraws = zeros(floor((ndraws-discarddraws)/thin), nparams);
+if ~options_.noprint
+    disp('surgibbs: estimating, please wait...')
+end
+
+hh = dyn_waitbar(0,'Please wait. Gibbs sampler...');
+set(hh,'Name','Surgibbs estimation.');
+residdraws = zeros(floor((ndraws-discarddraws)/thin), nobs, m);
+for i = 1:ndraws
+    if ~mod(i,10)
+        dyn_waitbar(i/ndraws,hh,'Please wait. Gibbs sampler...');
+    end
+    % Draw Omega, given X, Y, Beta
+    resid = reshape(Y - X*beta, nobs, m);
+    Omega = rand_inverse_wishart(m, nobs, chol(inv(resid'*resid/nobs)));
+
+    % Draw beta, given X, Y, Omega
+    tmp = kron(inv(Omega), eye(nobs));
+    tmp1 = X'*tmp*X;
+    Omegabar = inv(tmp1 + A);
+    betahat = tmp1\X'*tmp*Y;
+    betabar = Omegabar*(tmp1*betahat+A*beta0);
+    beta = rand_multivariate_normal(betabar', chol(Omegabar), nparams)';
+    if i > discarddraws
+        if thinidx == thin
+            oo_.surgibbs.(model_name).betadraws(drawidx, 1:nparams) = beta';
+            residdraws(drawidx, 1:nobs, 1:m) = resid;
+            thinidx = 1;
+            drawidx = drawidx + 1;
+        else
+            thinidx = thinidx + 1;
+        end
+    end
+end
+dyn_waitbar_close(hh);
+
+%
+% Save results.
+%
+
+oo_.surgibbs.(model_name).posterior.mean.beta = (sum(oo_.surgibbs.(model_name).betadraws)/rows(oo_.surgibbs.(model_name).betadraws))';
+oo_.surgibbs.(model_name).posterior.variance.beta = cov(oo_.surgibbs.(model_name).betadraws);
+
+% Yhat
+oo_.surgibbs.(model_name).Yhat = X*oo_.surgibbs.(model_name).posterior.mean.beta;
+oo_.surgibbs.(model_name).YhatOrig = oo_.surgibbs.(model_name).Yhat;
+oo_.surgibbs.(model_name).Yobs = Y;
+
+% Residuals
+oo_.surgibbs.(model_name).resid = Y - oo_.surgibbs.(model_name).Yhat;
+
+% Correct Yhat reported back to user
+oo_.surgibbs.(model_name).Yhat = oo_.surgibbs.(model_name).Yhat + lhssub;
+yhatname = [model_name '_FIT'];
+ds.(yhatname) = dseries(oo_.surgibbs.(model_name).Yhat,  fp, yhatname);
+
+% Compute and save posterior densities.
+for i=1:nparams
+    xx = oo_.surgibbs.(model_name).betadraws(:,i);
+    nn = length(xx);
+    bandwidth = mh_optimal_bandwidth(xx, nn, 0, 'gaussian');
+    [x, f] = kernel_density_estimate(xx, 512, nn, bandwidth, 'gaussian');
+    oo_.surgibbs.(model_name).posterior.density.(param_names{i}) = [x, f];
+end
+
+% Update model1s parameters with posterior mean.
+oo_.surgibbs.(model_name).param_idxs = zeros(length(param_names), 1);
+for i = 1:length(param_names)
+     if ~strcmp(param_names{i}, 'intercept')
+         oo_.surgibbs.(model_name).param_idxs(i) = find(strcmp(M_.param_names, param_names{i}));
+         M_.params(oo_.surgibbs.(model_name).param_idxs(i)) = oo_.surgibbs.(model_name).posterior.mean.beta(i);
+     end
+end
+oo_.surgibbs.(model_name).pnames = param_names;
+oo_.surgibbs.(model_name).neqs = m;
+
+% Estimate for sigma^2
+SS_res = oo_.surgibbs.(model_name).resid'*oo_.surgibbs.(model_name).resid;
+oo_.surgibbs.(model_name).s2 = SS_res/oo_.surgibbs.(model_name).dof;
+
+% Set appropriate entries in Sigma_e
+posterior_mean_resid = reshape((sum(residdraws))/rows(residdraws), nobs, m);
+Sigma_e = posterior_mean_resid'*posterior_mean_resid/oo_.surgibbs.(model_name).dof;
+
+% System R² value of McElroy (1977) - formula from Judge et al. (1986, p. 477)
+%
+% The R² is computed at the posterior mean of the estimated
+% parameters. Maybe it would make more sense to compute a posterior
+% distribution for this statistic…
+oo_.surgibbs.(model_name).R2 = 1 - (oo_.surgibbs.(model_name).resid' * kron(inv(Sigma_e), eye(nobs)) * oo_.surgibbs.(model_name).resid) ...
+                                 / (oo_.surgibbs.(model_name).Yobs' * kron(inv(Sigma_e), eye(nobs)-ones(nobs,nobs)/nobs) * oo_.surgibbs.(model_name).Yobs);
+
+% Write .inc file
+write_param_init_inc_file('surgibbs', model_name, oo_.surgibbs.(model_name).param_idxs, oo_.surgibbs.(model_name).posterior.mean.beta);
+
+%
+% Print Output
+%
+
+if ~options_.noprint
+    ttitle = 'Gibbs Sampling on SUR';
+    preamble = {['Model name: ' model_name], ...
+        sprintf('No. Equations: %d', oo_.surgibbs.(model_name).neqs), ...
+        sprintf('No. Independent Variables: %d', size(X, 2)), ...
+        sprintf('Observations: %d', oo_.surgibbs.(model_name).dof)};
+
+    afterward = {sprintf('s^2: %f', oo_.surgibbs.(model_name).s2), sprintf('R^2: %f', oo_.surgibbs.(model_name).R2)};
+    dyn_table(ttitle, preamble, afterward, param_names,...
+             {'Posterior mean', 'Posterior std.'}, 4,...
+             [oo_.surgibbs.(model_name).posterior.mean.beta, sqrt(diag(oo_.surgibbs.(model_name).posterior.variance.beta))]);
+end
+
+%
+% Plot
+%
+
+if ~options_.nograph
+    figure
+    nrows = 5;
+    ncols = floor(nparams/nrows);
+    if mod(nparams, nrows) ~= 0
+        ncols = ncols + 1;
+    end
+    for j = 1:length(param_names)
+        subplot(nrows, ncols, j)
+        histogram(oo_.surgibbs.(model_name).betadraws(:, j))
+        hc = histcounts(oo_.surgibbs.(model_name).betadraws(:, j));
+        line([oo_.surgibbs.(model_name).posterior.mean.beta(j) oo_.surgibbs.(model_name).posterior.mean.beta(j)], [min(hc) max(hc)], 'Color', 'red');
+        title(param_names{j}, 'Interpreter', 'none')
+    end
+end
+end
diff --git a/matlab/trust_region.m b/matlab/trust_region.m
index b0e8566dbdf210e19cb321e60bfa6ca2c5194727..5069a37dfe189b74f153194a6a8ef1b2c3bf9f60 100644
--- a/matlab/trust_region.m
+++ b/matlab/trust_region.m
@@ -25,7 +25,7 @@ function [x,check,info] = trust_region(fcn,x0,j1,j2,jacobian_flag,gstep,tolf,tol
 %    none
 
 % Copyright (C) 2008-2012 VZLU Prague, a.s.
-% Copyright (C) 2014-2019 Dynare Team
+% Copyright (C) 2014-2020 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -95,14 +95,7 @@ while (niter < maxiter && ~info)
         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);
+        dg = max (dg, jcn);
     end
 
     if (niter == 1)
@@ -195,7 +188,7 @@ end
 
 function x = dogleg (r, b, d, delta)
 % Get Gauss-Newton direction.
-x = r \ b;
+x = decomposition(r, 'CheckCondition', false) \ b;
 xn = norm (d .* x);
 if (xn > delta)
     % GN is too big, get scaled gradient.
@@ -225,3 +218,4 @@ if (xn > delta)
     x = alpha * x + ((1-alpha) * min (snm, delta)) * s;
 end
 end
+
diff --git a/matlab/update_all_parameters_in_workspace.m b/matlab/update_all_parameters_in_workspace.m
new file mode 100644
index 0000000000000000000000000000000000000000..64e1515ee601e111a6b215d3c14833cd946505f8
--- /dev/null
+++ b/matlab/update_all_parameters_in_workspace.m
@@ -0,0 +1,24 @@
+function update_all_parameters_in_workspace(DynareModel)
+
+% Updates all parameter values in Matlab/Octave base workspace.
+
+% Copyright (C) 2018 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/>.
+
+for i=1:length(DynareModel.params)
+    assignin('base', DynareModel.param_names{i}, DynareModel.params(i));
+end
\ No newline at end of file
diff --git a/matlab/user_has_octave_forge_package.m b/matlab/user_has_octave_forge_package.m
index 3b0abf484921fc5ca6b248db8198251c2946cf25..e67e511118a1ba082631a75f6f7957ca3e363f37 100644
--- a/matlab/user_has_octave_forge_package.m
+++ b/matlab/user_has_octave_forge_package.m
@@ -26,12 +26,11 @@ if isequal(flag{1,1}, "Not installed")
 else
     if isequal(flag{1,1}, "Not loaded")
         pkg("load", package);
-    endif
+    end
     if nargin > 1 && compare_versions(desc{1,1}.version, min_version, "<")
         hasPackage = 0;
     else
         hasPackage = 1;
-    endif
-endif
-endfunction
-
+    end
+end
+end
\ No newline at end of file
diff --git a/matlab/var_forecast.m b/matlab/var_forecast.m
new file mode 100644
index 0000000000000000000000000000000000000000..d1de12e1c29c11677397081b9bd17a04bfa13d73
--- /dev/null
+++ b/matlab/var_forecast.m
@@ -0,0 +1,103 @@
+function y = var_forecast(name, h, y, fcv)
+
+% name : filename
+% name        string    name of var model, provided in var statement
+% h           int       number of steps-ahead forecast
+% y           matrix    rows: realizations of endogenous variables in declaration order; cols: realizations in t, t-1, t-2 ... order of VAR
+% fcv         string    name of variable we want forecast for
+
+% returns the h-step-ahead VAR(order) forecast for fcv
+
+% example calling:
+% In Matlab:
+% >> autoregressive_matrices{1} = [0.5000    0.1000; 0.4000    0.5000];
+% >> autoregressive_matrices{2} = [0         0     ; 0.2500    0     ];
+% >> mu                         = [0.0200; 0.0300];
+% >> save('m1.mat', 'mu','autoregressive_matrices');
+
+% In .mod file:
+% var a b c d;
+% ...
+% var(model_name=m1,order=2) a c;
+
+% From Matlab backend:
+% >> yt   = [0.0600;    33.0000;    0.0300;    22.0000];
+% >> ytm1 = [0.0550;    11.0000;    0.0300;    88.0000];
+% >> var_forecast('m1', 1, [yt ytm1])
+% >> var_forecast('m1', 2, [yt ytm1], ['a'])
+
+%%
+global M_;
+
+%% construct y
+assert( ...
+    length(y) == length(M_.endo_names) ||             ... % when called from static model
+    length(y) == sum(sum(M_.lead_lag_incidence ~= 0)) ... % when called from dynamic model
+    );
+yidx = zeros(size(M_.endo_names));
+for i=1:size(M_.var.(name).var_list_,1)
+    yidx = yidx | strcmp(strtrim(M_.var.(name).var_list_(i,:)), M_.endo_names);
+end
+y = y(yidx,:);
+
+if nargin == 4
+    fvidx = strcmp(fcv, M_.endo_names);
+end
+
+%% load .mat file
+load(name, 'autoregressive_matrices', 'mu');
+if ~exist('autoregressive_matrices', 'var') || ~exist('mu', 'var')
+    error([name ' : must contain the variables autoregressive_matrices and mu']);
+end
+assert(h >= 1);
+
+%% rewrite as VAR(1)
+lm = length(mu);
+lc = length(autoregressive_matrices);
+assert(lc == M_.var.(name).order);
+if size(y,1) ~= lm || size(y,2) ~= M_.var.(name).order
+    error('The dimensions of y are not correct. It should be an nvars x order matrix');
+end
+
+A = zeros(lm*lc, lm*lc);
+for i=1:lc
+    if any([lm lm] ~= size(autoregressive_matrices{i}))
+        error('The dimensions of mu and autoregressive_matrices are off');
+    end
+    col = lm*(i-1)+1:lm*i;
+    A(1:lm, col) = autoregressive_matrices{i};
+    if i ~= lc
+        A(lm*i+1:lm*i+lm, col) = eye(lm, lm);
+    end
+end
+if M_.var.(name).order > 1
+    mu = [mu; zeros(lm*M_.var.(name).order-lm, 1)];
+end
+
+%% Calculate Forecast
+%  New Introduction to Multiple Time Series Analysis
+%  Helmut Lutkepohl
+%  page 34
+%
+% An = eye(size(A));
+% for i=1:h-1
+%     An = An + A^i;
+% end
+% y = An*mu + A^h*y(:);
+
+for i=1:h
+    y = mu + A*y(:);
+end
+y = y(1:lm);
+
+if nargin == 4
+    retidx = find(fvidx & yidx == 1);
+    if isempty(retidx)
+        return;
+    elseif retidx == 1
+        y = y(1);
+    else
+        y = y(sum(yidx(1:retidx-1))+1);
+    end
+end
+end
\ No newline at end of file
diff --git a/matlab/writeVarExpectationFunction.m b/matlab/writeVarExpectationFunction.m
new file mode 100644
index 0000000000000000000000000000000000000000..0e9a9d8d690661217ef804720a4cd40952d4ebf8
--- /dev/null
+++ b/matlab/writeVarExpectationFunction.m
@@ -0,0 +1,182 @@
+function writeVarExpectationFunction(var_model_name, horizon)
+% function writeVarExpectationFunction(var_model_name, horizon)
+% Writes the var_forecast_<<var_model_name>>.m file
+%
+% INPUTS
+%
+%   var_model_name   [string]        the name of the VAR model
+%
+%   horizon          [int]           the forecast horizon
+%
+% OUTPUTS
+%
+%   NONE
+
+% Copyright (C) 2017-2018 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/>.
+
+%%
+global M_;
+
+%% open file
+basename = ['var_forecast_' var_model_name];
+fid = fopen([basename '.m'], 'w');
+if fid == -1
+    error(['Could not open ' basename '.m for writing']);
+end
+
+%% load .mat file
+load(var_model_name, 'autoregressive_matrices', 'mu');
+if ~exist('autoregressive_matrices', 'var') || ~exist('mu', 'var')
+    error([var_model_name '.mat : must contain the variables autoregressive_matrices and mu']);
+end
+
+%%
+fprintf(fid, 'function ret = %s(y)\n', basename);
+fprintf(fid, '%%function ret = %s(y)\n', basename);
+fprintf(fid, '%% Calculates the %d-step-ahead forecast from the VAR model %s\n', max(horizon), var_model_name);
+fprintf(fid, '%%\n%% Created automatically by Dynare on %s\n%%\n\n', datestr(now));
+fprintf(fid, '%%%% Construct y\n');
+fprintf(fid, 'assert(length(y) == %d);\n', sum(sum(M_.lead_lag_incidence ~= 0)));
+
+nvars = size(M_.var.(var_model_name).var_list_,1);
+var_model_order = M_.var.(var_model_name).order;
+yidx = zeros(nvars, min(var_model_order, 2));
+% first for order <= 2, drawing variables directly from their M_.endo_names
+for i=1:min(var_model_order, 2)
+    if mod(i, 2) == 0
+        ridx = 1;
+    else
+        ridx = 2;
+    end
+    for j=1:nvars
+        cidx = strcmp(strtrim(M_.var.(var_model_name).var_list_(j,:)), M_.endo_names)';
+        if ~any(cidx)
+            error([strtrim(M_.var.(var_model_name).var_list_(j,:)) ' not found in the list of endogenous variables']);
+        end
+        yidx(j, i) = M_.lead_lag_incidence(ridx, cidx);
+    end
+end
+yidx = yidx(:);
+
+% then for order > 2
+if var_model_order > 2
+    y1idx = zeros((var_model_order - 2)*nvars, var_model_order - 2);
+    for i=3:var_model_order
+        for j=1:nvars
+            idx = find(strcmp(strtrim(M_.var.(var_model_name).var_list_(j,:)), M_.endo_names));
+            if ~any(idx)
+                error([strtrim(M_.var.(var_model_name).var_list_(j,:)) ' not found in the list of endogenous variables']);
+            end
+            varidx = [M_.aux_vars.orig_index] == idx & [M_.aux_vars.orig_lead_lag] == -i;
+            cidx = [M_.aux_vars.endo_index];
+            cidx = cidx(varidx);
+            y1idx(j, i-2) = M_.lead_lag_incidence(2, cidx);
+        end
+    end
+    yidx = [yidx ; y1idx(:)];
+end
+
+if any(yidx == 0)
+    fprintf(fid, 'y = [');
+    for i = 1:length(yidx)
+        if i ~= 1
+            fprintf(fid, '; ');
+        end
+        if yidx(i) == 0
+            fprintf(fid, '0');
+        else
+            fprintf(fid, 'y(%d)', yidx(i));
+        end
+    end
+    fprintf(fid, '];\n');
+else
+    fprintf(fid, 'y = y([');
+    fprintf(fid, '%d ', yidx);
+    fprintf(fid, ']);\n');
+end
+
+lm = length(mu);
+lc = length(autoregressive_matrices);
+assert(lc == var_model_order);
+
+A = zeros(lm*lc, lm*lc);
+for i=1:lc
+    if any([lm lm] ~= size(autoregressive_matrices{i}))
+        error(['The dimensions of mu and autoregressive_matrices for ' var_model_name ' are off']);
+    end
+    col = lm*(i-1)+1:lm*i;
+    A(1:lm, col) = autoregressive_matrices{i};
+    if i ~= lc
+        A(lm*i+1:lm*i+lm, col) = eye(lm, lm);
+    end
+end
+if var_model_order > 1
+    mu = [mu; zeros(lm*var_model_order-lm, 1)];
+end
+fprintf(fid, '\n%%%% Calculate %d-step-ahead forecast for VAR(%d) written as VAR(1)\n', max(horizon), var_model_order);
+fprintf(fid, '%%  Follows L�tkepohl (2005) pg 15 & 34\n');
+if max(horizon) == 1
+    printInsideOfLoop(fid, mu, A, false);
+    fprintf(fid, 'ret(1, :) = y(1:%d);\n', lm);
+else
+    if length(horizon) ~= 1
+        fprintf(fid, 'retidx = 1;\n');
+        fprintf(fid, 'ret = zeros(%d, %d);\n', length(horizon), lm);
+    end
+
+    fprintf(fid, 'for i=1:%d\n', max(horizon));
+    printInsideOfLoop(fid, mu, A, true);
+    if length(horizon) ~= 1
+        fprintf(fid, '    if any([');
+        fprintf(fid, '%d ', horizon);
+        fprintf(fid, '] == i)\n');
+        fprintf(fid, '        %% If we want a forecast at more than one\n');
+        fprintf(fid, '        %% horizon save it in ''ret'' when encountered\n');
+        fprintf(fid, '        ret(retidx, :) = y(1:%d);\n', lm);
+        fprintf(fid, '        retidx = retidx + 1;\n');
+        fprintf(fid, '    end\n');
+    end
+
+    fprintf(fid, 'end\n');
+
+    if length(horizon) == 1
+        fprintf(fid, 'ret(1, :) = y(1:%d);\n', lm);
+    end
+end
+
+%% close file
+fprintf(fid, 'end\n');
+fclose(fid);
+end
+
+function printInsideOfLoop(fid, mu, A, inloop)
+if inloop
+    fs = '    ';
+    ns = '       ';
+    spaces = '        ';
+else
+    fs = '';
+    ns = '   ';
+    spaces = '    ';
+end
+fprintf(fid, '%sy = ...\n%s[ ... %% intercept\n%s', fs, spaces, ns);
+    fprintf(fid, [repmat('% f ', 1, size(mu, 2)) '; ...\n' ns], mu');
+fprintf(fid, ' ] + ...\n%s[ ... %% autoregressive matrices\n%s', spaces, ns);
+    fprintf(fid, [repmat('% f ', 1, size(A, 2)) '; ...\n' ns], A');
+fprintf(fid, ' ] * y;\n');
+end
\ No newline at end of file
diff --git a/matlab/write_expectations.m b/matlab/write_expectations.m
new file mode 100644
index 0000000000000000000000000000000000000000..273ebded3cb6d60147b29900bc64de279845bb65
--- /dev/null
+++ b/matlab/write_expectations.m
@@ -0,0 +1,157 @@
+function [expression, growthneutralitycorrection] = write_expectations(eqname, expectationmodelname, expectationmodelkind, iscrlf)
+
+% Prints the exansion of the VAR_EXPECTATION or PAC_EXPECTATION term in files.
+%
+% INPUTS
+% - eqname                      [string]    Name of the equation.
+% - epxpectationmodelname       [string]    Name of the expectation model.
+% - expectationmodelkind        [string]    Kind of the expectation model ('var' or 'pac').
+% - iscrlf                      [string]    Adds carriage return after each additive term if true.
+%
+% OUTPUTS
+% - expression                  [string]    Unrolled expectation expression.
+% - growthneutralitycorrection  [string]
+
+% Copyright (C) 2019 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/>.
+
+global M_
+
+if ismember(expectationmodelkind, {'var', 'pac'})
+    if isequal(expectationmodelkind, 'var')
+        expectationmodelfield = 'var_expectation';
+    else
+        expectationmodelfield = 'pac';
+        % Get the equation tag (in M_.pac.(pacmodl).equations)
+        eqtag = M_.pac.(expectationmodelname).tag_map{strcmp(M_.pac.(expectationmodelname).tag_map(:,1), eqname),2};
+    end
+else
+    error('Value of third input argument must be ''var'' or ''pac''.')
+end
+
+expectationmodel = M_.(expectationmodelfield).(expectationmodelname);
+
+if nargout>1 && isequal(expectationmodelkind, 'var')
+    error('Cannot return more than one argument if the expectation model is a VAR.')
+end
+
+if nargin<4
+    iscrlf = false;
+end
+
+% Get the name of the associated VAR model and test its existence.
+if ~isfield(M_.(expectationmodel.auxiliary_model_type), expectationmodel.auxiliary_model_name)
+    switch expectationmodelkind
+      case 'var-expectations'
+        error('Unknown VAR/TREND_COMPONENT model (%s) in VAR_EXPECTATION_MODEL (%s)!', expectationmodel.auxiliary_model_name, expectationmodelname)
+      case 'pac-expectations'
+        error('Unknown VAR/TREND_COMPONENT model (%s) in PAC_EXPECTATION_MODEL (%s)!', expectationmodel.auxiliary_model_name, expectationmodelname)
+      otherwise
+    end
+end
+
+auxmodel = M_.(expectationmodel.auxiliary_model_type).(expectationmodel.auxiliary_model_name);
+
+maxlag = max(auxmodel.max_lag);
+if isequal(expectationmodel.auxiliary_model_type, 'trend_component')
+    % Need to add a lag since the error correction equations are rewritten in levels.
+    maxlag = maxlag+1;
+end
+
+id = 0;
+
+for i=1:maxlag
+    for j=1:length(auxmodel.list_of_variables_in_companion_var)
+        id = id+1;
+        variable = auxmodel.list_of_variables_in_companion_var{j};
+        transformations = {};
+        ida = get_aux_variable_id(variable);
+        op = 0;
+        while ida
+            op = op+1;
+            if isequal(M_.aux_vars(ida).type, 8)
+                transformations(op) = {'diff'};
+                variable = M_.endo_names{M_.aux_vars(ida).orig_index};
+                ida = get_aux_variable_id(variable);
+            elseif isequal(M_.aux_vars(ida).type, 10)
+                transformations(op) = {M_.aux_vars(ida).unary_op};
+                variable = M_.endo_names{M_.aux_vars(ida).orig_index};
+                ida = get_aux_variable_id(variable);
+            else
+                error('This case is not implemented.')
+            end
+        end
+        switch expectationmodelkind
+          case 'var'
+            parameter = M_.param_names{expectationmodel.param_indices(id)};
+          case 'pac'
+            parameter = '';
+            if ~isempty(expectationmodel.equations.(eqtag).h0_param_indices)
+                parameter = M_.param_names{expectationmodel.equations.(eqtag).h0_param_indices(id)};
+            end
+            if ~isempty(expectationmodel.equations.(eqtag).h1_param_indices)
+                if isempty(parameter)
+                    parameter = M_.param_names{expectationmodel.equations.(eqtag).h1_param_indices(id)};
+                else
+                    parameter = sprintf('(%s+%s)', parameter, M_.param_names{expectationmodel.equations.(eqtag).h1_param_indices(id)});
+                end
+            end
+          otherwise
+        end
+        switch expectationmodelkind
+          case 'var'
+            if i>1
+                variable = sprintf('%s(-%d)', variable, i-1);
+            end
+          case 'pac'
+            variable = sprintf('%s(-%d)', variable, i);
+          otherwise
+        end
+        if ~isempty(transformations)
+            for k=length(transformations):-1:1
+                variable = sprintf('%s(%s)', transformations{k}, variable);
+            end
+        end
+        if isequal(id, 1)
+            if iscrlf
+                expression = sprintf('%s*%s\n', parameter, variable);
+            else
+                expression = sprintf('%s*%s', parameter, variable);
+            end
+        else
+            if iscrlf
+                expression = sprintf('%s + %s*%s\n', expression, parameter, variable);
+            else
+                expression = sprintf('%s + %s*%s', expression, parameter, variable);
+            end
+        end
+    end
+end
+
+if isfield(expectationmodel, 'growth_neutrality_param_index')
+    if numel(expectationmodel.growth_linear_comb) == 1
+        growthneutralitycorrection = sprintf('%s*%s', M_.param_names{expectationmodel.growth_neutrality_param_index}, expectationmodel.growth_str);
+    else
+        growthneutralitycorrection = sprintf('%s*(%s)', M_.param_names{expectationmodel.growth_neutrality_param_index}, expectationmodel.growth_str);
+    end
+else
+    growthneutralitycorrection = '';
+end
+
+if nargout==1 && ~isempty(growthneutralitycorrection)
+    expression = sprintf('%s + %s', expression, growthneutralitycorrection);
+end
\ No newline at end of file
diff --git a/mex/build/block_trust_region.am b/mex/build/block_trust_region.am
new file mode 100644
index 0000000000000000000000000000000000000000..0a3e3f8e03ace8ba34d7501e3fb9566d96f142d4
--- /dev/null
+++ b/mex/build/block_trust_region.am
@@ -0,0 +1,26 @@
+mex_PROGRAMS = block_trust_region
+
+nodist_block_trust_region_SOURCES = \
+	dulmage_mendelsohn.f08 \
+	matlab_fcn_closure.f08 \
+	trust_region.f08 \
+	mexFunction.f08 \
+	matlab_mex.F08 \
+	blas_lapack.F08
+
+BUILT_SOURCES = $(nodist_block_trust_region_SOURCES)
+CLEANFILES = $(nodist_block_trust_region_SOURCES)
+
+dulmage_mendelsohn.o: matlab_mex.mod
+dulmage_mendelsohn.mod: dulmage_mendelsohn.o
+
+matlab_fcn_closure.mod: matlab_fcn_closure.o
+matlab_fcn_closure.o: matlab_mex.mod
+
+trust_region.mod: trust_region.o
+trust_region.o: lapack.mod
+
+mexFunction.o: matlab_mex.mod dulmage_mendelsohn.mod matlab_fcn_closure.mod trust_region.mod
+
+%.f08: $(top_srcdir)/../../sources/block_trust_region/%.f08
+	$(LN_S) -f $< $@
diff --git a/mex/build/matlab/Makefile.am b/mex/build/matlab/Makefile.am
index 8bad19f68ed65d81ddedc38a3b930dc4a8dca9e7..e84baee6ed388fe01510b7a2d7a63d0e045b98b4 100644
--- a/mex/build/matlab/Makefile.am
+++ b/mex/build/matlab/Makefile.am
@@ -1,6 +1,6 @@
 ACLOCAL_AMFLAGS = -I ../../../m4
 
-SUBDIRS = mjdgges kronecker bytecode block_kalman_filter sobol perfect_foresight_problem num_procs disclyap_fast
+SUBDIRS = mjdgges kronecker bytecode block_kalman_filter sobol perfect_foresight_problem num_procs block_trust_region disclyap_fast
 
 # libdynare++ must come before gensylv, k_order_perturbation, dynare_simul_
 if ENABLE_MEX_DYNAREPLUSPLUS
diff --git a/mex/build/matlab/block_trust_region/Makefile.am b/mex/build/matlab/block_trust_region/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..2cc2868d661969622924a372d553406d5cbed886
--- /dev/null
+++ b/mex/build/matlab/block_trust_region/Makefile.am
@@ -0,0 +1,2 @@
+include ../mex.am
+include ../../block_trust_region.am
diff --git a/mex/build/matlab/configure.ac b/mex/build/matlab/configure.ac
index 69f3670a9e43930f48d22f0cb25a909685530957..c9460676a4172feab47f6c316d34f1c8f1b22cb1 100644
--- a/mex/build/matlab/configure.ac
+++ b/mex/build/matlab/configure.ac
@@ -156,10 +156,11 @@ AC_CONFIG_FILES([Makefile
                  kalman_steady_state/Makefile
                  ms_sbvar/Makefile
                  block_kalman_filter/Makefile
-	         sobol/Makefile
-		 local_state_space_iterations/Makefile
+	             sobol/Makefile
+		         local_state_space_iterations/Makefile
                  perfect_foresight_problem/Makefile
                  num_procs/Makefile
+                 block_trust_region/Makefile
                  disclyap_fast/Makefile])
 
 AC_OUTPUT
diff --git a/mex/build/octave/Makefile.am b/mex/build/octave/Makefile.am
index c9e1f91569fde8f9dfed65af85326b2cd8005aa0..6726be71e928d36dc9cac5cb8deebed59ebf1b60 100644
--- a/mex/build/octave/Makefile.am
+++ b/mex/build/octave/Makefile.am
@@ -1,6 +1,6 @@
 ACLOCAL_AMFLAGS = -I ../../../m4
 
-SUBDIRS = mjdgges kronecker bytecode block_kalman_filter sobol perfect_foresight_problem num_procs disclyap_fast
+SUBDIRS = mjdgges kronecker bytecode block_kalman_filter sobol perfect_foresight_problem num_procs block_trust_region disclyap_fast
 
 # libdynare++ must come before gensylv, k_order_perturbation, dynare_simul_
 if ENABLE_MEX_DYNAREPLUSPLUS
diff --git a/mex/build/octave/block_trust_region/Makefile.am b/mex/build/octave/block_trust_region/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..40cbddc16d0a3fdc9815864a0bf02e2eb63f19e0
--- /dev/null
+++ b/mex/build/octave/block_trust_region/Makefile.am
@@ -0,0 +1,3 @@
+EXEEXT = .mex
+include ../mex.am
+include ../../block_trust_region.am
diff --git a/mex/build/octave/configure.ac b/mex/build/octave/configure.ac
index c793d4db3d5ba6475a8ee4cba987486aea6e7af2..6f7f9391549c2f5a734ad47b57fcf70750778469 100644
--- a/mex/build/octave/configure.ac
+++ b/mex/build/octave/configure.ac
@@ -146,10 +146,11 @@ AC_CONFIG_FILES([Makefile
                  kalman_steady_state/Makefile
                  ms_sbvar/Makefile
                  block_kalman_filter/Makefile
-		 sobol/Makefile
-		 local_state_space_iterations/Makefile
+		         sobol/Makefile
+		         local_state_space_iterations/Makefile
                  perfect_foresight_problem/Makefile
                  num_procs/Makefile
+                 block_trust_region/Makefile
                  disclyap_fast/Makefile])
 
 AC_OUTPUT
diff --git a/mex/sources/Makefile.am b/mex/sources/Makefile.am
index e04b7983fd418b6f0f6e2d5f2dfffc03688e1d2c..3fca510decf6c3826ff2a9ea512e84e32d251b9a 100644
--- a/mex/sources/Makefile.am
+++ b/mex/sources/Makefile.am
@@ -19,6 +19,7 @@ EXTRA_DIST = \
 	dynare_simul_ \
 	perfect_foresight_problem \
 	num_procs \
+	block_trust_region \
 	disclyap_fast
 
 clean-local:
diff --git a/mex/sources/block_trust_region/dulmage_mendelsohn.f08 b/mex/sources/block_trust_region/dulmage_mendelsohn.f08
new file mode 100644
index 0000000000000000000000000000000000000000..56122bedb62f9f8d427318993e2cffddd8870408
--- /dev/null
+++ b/mex/sources/block_trust_region/dulmage_mendelsohn.f08
@@ -0,0 +1,72 @@
+! Wrapper around MATLAB’s dmperm to compute the Dulmage-Mendelsohn
+! decomposition
+
+! Copyright © 2020 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/>.
+
+module dulmage_mendelsohn
+  use iso_fortran_env
+  use matlab_mex
+  implicit none
+
+  ! Represents a block in the fine DM decomposition
+  type :: dm_block
+     integer, dimension(:), allocatable :: row_indices, col_indices
+  end type dm_block
+contains
+  subroutine dm_blocks(mat, blocks)
+    real(real64), dimension(:, :), intent(in) :: mat
+    type(dm_block), dimension(:), allocatable, intent(out) :: blocks
+
+    type(c_ptr), dimension(1) :: call_rhs
+    type(c_ptr), dimension(4) :: call_lhs
+    real(real64), dimension(:, :), pointer :: mat_mx
+    real(real64), dimension(:), pointer :: p, q, r, s
+    integer :: i, j
+
+    call_rhs(1) = mxCreateDoubleMatrix(int(size(mat, 1), mwSize), int(size(mat, 2), mwSize), mxREAL)
+    mat_mx(1:size(mat,1), 1:size(mat,2)) => mxGetPr(call_rhs(1))
+    mat_mx = mat
+
+    if (mexCallMATLAB(4_c_int, call_lhs, 1_c_int, call_rhs, "dmperm") /= 0) &
+         call mexErrMsgTxt("Error calling dmperm")
+
+    call mxDestroyArray(call_rhs(1))
+
+    p => mxGetPr(call_lhs(1))
+    q => mxGetPr(call_lhs(2))
+    r => mxGetPr(call_lhs(3))
+    s => mxGetPr(call_lhs(4))
+
+    allocate(blocks(size(r)-1))
+    do i = 1, size(r)-1
+       allocate(blocks(i)%row_indices(int(r(i+1)-r(i))))
+       do j = 1, int(r(i+1)-r(i))
+          blocks(i)%row_indices(j) = int(p(j+int(r(i))-1))
+       end do
+       allocate(blocks(i)%col_indices(int(s(i+1)-s(i))))
+       do j = 1, int(s(i+1)-s(i))
+          blocks(i)%col_indices(j) = int(q(j+int(s(i))-1))
+       end do
+    end do
+
+    call mxDestroyArray(call_lhs(1))
+    call mxDestroyArray(call_lhs(2))
+    call mxDestroyArray(call_lhs(3))
+    call mxDestroyArray(call_lhs(4))
+  end subroutine dm_blocks
+end module dulmage_mendelsohn
diff --git a/mex/sources/block_trust_region/matlab_fcn_closure.f08 b/mex/sources/block_trust_region/matlab_fcn_closure.f08
new file mode 100644
index 0000000000000000000000000000000000000000..d6fc00ea8c4705a1ee56844225ba6324d27cf4b1
--- /dev/null
+++ b/mex/sources/block_trust_region/matlab_fcn_closure.f08
@@ -0,0 +1,103 @@
+! Encapsulates a MATLAB function from ℝⁿ to ℝⁿ
+! It must take as 1st argument the point where it is evaluated,
+! and return 1 or 2 arguments: value and, optionally, the Jacobian
+! The input is copied on entry, the output arguments are copied on exit.
+! It may also take extra arguments, which are stored in the module (hence the
+! latter is conceptually equivalent to a closure).
+!
+! Additionally, if x_indices and f_indices are associated, then the matlab_fcn
+! procedure only exposes a restricted version of the MATLAB procedure, limited
+! to the specified indices specified for x and f. In that case, x_all needs to
+! be set in order to give the input values for the indices that are not passed
+! to matlab_fcn.
+
+! Copyright © 2019-2020 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/>.
+
+module matlab_fcn_closure
+  use iso_c_binding
+  use matlab_mex
+  implicit none
+
+  private
+  public :: func, extra_args, f_indices, x_indices, x_all, matlab_fcn
+
+  type(c_ptr), pointer :: func => null()
+  type(c_ptr), dimension(:), pointer :: extra_args => null()
+  integer, dimension(:), pointer :: f_indices => null(), x_indices => null()
+  real(real64), dimension(:), pointer :: x_all => null()
+contains
+  subroutine matlab_fcn(x, fvec, fjac)
+    real(real64), dimension(:), intent(in) :: x
+    real(real64), dimension(size(x)), intent(out) :: fvec
+    real(real64), dimension(size(x), size(x)), intent(out), optional :: fjac
+
+    type(c_ptr), dimension(2) :: call_lhs
+    type(c_ptr), dimension(size(extra_args)+2) :: call_rhs
+    real(real64), dimension(:), pointer :: x_mat ! Needed to avoid gfortran ICE…
+    real(real64), dimension(:), pointer :: fvec_all
+    real(real64), dimension(:,:), pointer :: fjac_all
+    integer(c_int) :: nlhs
+    integer(mwSize) :: n_all
+
+    call_rhs(1) = func
+    if (associated(x_all)) then
+       n_all = size(x_all)
+    else
+       n_all = size(x)
+    end if
+    call_rhs(2) = mxCreateDoubleMatrix(n_all, 1_mwSize, mxREAL)
+    x_mat => mxGetPr(call_rhs(2))
+    if (associated(x_indices) .and. associated(x_all)) then
+       x_mat = x_all
+       x_mat(x_indices) = x
+    else
+       x_mat = x
+    end if
+    call_rhs(3:) = extra_args
+
+    if (present(fjac)) then
+       nlhs = 2
+    else
+       nlhs = 1
+    end if
+
+    ! We use "feval", because it’s the only way of evaluating a function handle through mexCallMATLAB
+    if (mexCallMATLAB(nlhs, call_lhs, int(size(call_rhs), c_int), call_rhs, "feval") /= 0) &
+         call mexErrMsgTxt("Error calling function to be solved")
+
+    call mxDestroyArray(call_rhs(2))
+
+    fvec_all => mxGetPr(call_lhs(1))
+    if (associated(f_indices)) then
+       fvec = fvec_all(f_indices)
+    else
+       fvec = fvec_all
+    end if
+    call mxDestroyArray(call_lhs(1))
+
+    if (present(fjac)) then
+       fjac_all(1:n_all,1:n_all) => mxGetPr(call_lhs(2))
+       if (associated(x_indices) .and. associated(f_indices)) then
+          fjac = fjac_all(f_indices, x_indices)
+       else
+          fjac = fjac_all
+       end if
+       call mxDestroyArray(call_lhs(2))
+    end if
+  end subroutine matlab_fcn
+end module matlab_fcn_closure
diff --git a/mex/sources/block_trust_region/mexFunction.f08 b/mex/sources/block_trust_region/mexFunction.f08
new file mode 100644
index 0000000000000000000000000000000000000000..35d9e7d7aeb7b7ea472d216ffc8ea8aa1a935b5c
--- /dev/null
+++ b/mex/sources/block_trust_region/mexFunction.f08
@@ -0,0 +1,251 @@
+! Copyright © 2019-2020 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/>.
+
+subroutine mexFunction(nlhs, plhs, nrhs, prhs) bind(c, name='mexFunction')
+  use iso_fortran_env
+  use iso_c_binding
+  use dulmage_mendelsohn
+  use matlab_mex
+  use matlab_fcn_closure
+  use trust_region
+  implicit none
+
+  type(c_ptr), dimension(*), intent(in), target :: prhs
+  type(c_ptr), dimension(*), intent(out) :: plhs
+  integer(c_int), intent(in), value :: nlhs, nrhs
+
+  real(real64), dimension(:), allocatable, target :: x
+  type(dm_block), dimension(:), allocatable, target :: blocks
+  integer :: info, i
+  real(real64) :: tolf, tolx
+  integer :: maxiter
+  real(real64), dimension(:), allocatable :: fvec
+  real(real64), dimension(:,:), allocatable :: fjac
+  logical :: debug, specializedunivariateblocks
+  character(len=80) :: debug_msg
+  logical(mxLogical), dimension(:), pointer :: isloggedlhs => null(), &
+       isauxdiffloggedrhs => null()
+  type(c_ptr) :: endo_names, lhs
+  logical :: fre ! True if the last block has been solved (i.e. not evaluated), so that residuals must be updated
+  integer, dimension(:), allocatable :: evaled_cols ! If fre=.false., lists the columns that have been evaluated so far without updating the residuals
+
+  if (nrhs < 4 .or. nlhs /= 2) then
+     call mexErrMsgTxt("Must have at least 7 inputs and exactly 2 outputs")
+     return
+  end if
+
+  if (.not. ((mxIsChar(prhs(1)) .and. mxGetM(prhs(1)) == 1) .or. mxIsClass(prhs(1), "function_handle"))) then
+     call mexErrMsgTxt("First argument (function) should be a string or a function handle")
+     return
+  end if
+
+  if (.not. (mxIsDouble(prhs(2)) .and. (mxGetM(prhs(2)) == 1 .or. mxGetN(prhs(2)) == 1))) then
+     call mexErrMsgTxt("Second argument (initial guess) should be a real vector")
+     return
+  end if
+
+  if (.not. (mxIsScalar(prhs(3)) .and. mxIsNumeric(prhs(3)))) then
+     call mexErrMsgTxt("Third argument (tolf) should be a numeric scalar")
+     return
+  end if
+
+  if (.not. (mxIsScalar(prhs(4)) .and. mxIsNumeric(prhs(4)))) then
+     call mexErrMsgTxt("Fourth argument (tolx) should be a numeric scalar")
+     return
+  end if
+
+  if (.not. (mxIsScalar(prhs(5)) .and. mxIsNumeric(prhs(5)))) then
+     call mexErrMsgTxt("Fifth argument (maxiter) should be a numeric scalar")
+     return
+  end if
+
+  if (.not. (mxIsLogicalScalar(prhs(6)))) then
+     call mexErrMsgTxt("Sixth argument (debug) should be a logical scalar")
+     return
+  end if
+
+  if (.not. (mxIsStruct(prhs(7)) .and. &
+       (mxGetNumberOfFields(prhs(7)) == 0 .or. mxGetNumberOfFields(prhs(7)) == 4))) then
+     call mexErrMsgTxt("Seventh argument should be a struct with either 0 or 4 fields")
+     return
+  end if
+  specializedunivariateblocks = (mxGetNumberOfFields(prhs(7)) == 4)
+
+  func => prhs(1)
+  tolf = mxGetScalar(prhs(3))
+  tolx = mxGetScalar(prhs(4))
+  maxiter = int(mxGetScalar(prhs(5)))
+  debug = mxGetScalar(prhs(6)) == 1._c_double
+  extra_args => prhs(8:nrhs) ! Extra arguments to func are in argument 8 and subsequent ones
+  associate (x_mat => mxGetPr(prhs(2)))
+    allocate(x(size(x_mat)))
+    x = x_mat
+  end associate
+  if (specializedunivariateblocks) then
+     block
+       type(c_ptr) :: tmp
+       tmp = mxGetField(prhs(7), 1_mwIndex, "isloggedlhs")
+       if (.not. (c_associated(tmp) .and. mxIsLogical(tmp) .and. mxGetNumberOfElements(tmp) == size(x))) then
+          call mexErrMsgTxt("Seventh argument must have a 'isloggedlhs' field of type logical, of same size as second argument")
+          return
+       end if
+       isloggedlhs => mxGetLogicals(tmp)
+
+       tmp = mxGetField(prhs(7), 1_mwIndex, "isauxdiffloggedrhs")
+       if (.not. (c_associated(tmp) .and. mxIsLogical(tmp) .and. mxGetNumberOfElements(tmp) == size(x))) then
+          call mexErrMsgTxt("Seventh argument must have a 'isauxdiffloggedrhs' field of type &
+               &logical, of same size as second argument")
+          return
+       end if
+       isauxdiffloggedrhs => mxGetLogicals(tmp)
+
+       lhs = mxGetField(prhs(7), 1_mwIndex, "lhs")
+       if (.not. (c_associated(lhs) .and. mxIsCell(lhs) .and. mxGetNumberOfElements(lhs) == size(x))) then
+          call mexErrMsgTxt("Seventh argument must have a 'lhs' field of type cell, of same size as second argument")
+          return
+       end if
+
+       endo_names = mxGetField(prhs(7), 1_mwIndex, "endo_names")
+       if (.not. (c_associated(endo_names) .and. mxIsCell(endo_names) .and. mxGetNumberOfElements(endo_names) == size(x))) then
+          call mexErrMsgTxt("Seventh argument must have a 'endo_names' field of type cell, of same size as second argument")
+          return
+       end if
+     end block
+
+     allocate(evaled_cols(0))
+     fre = .false.
+  end if
+
+  allocate(fvec(size(x)))
+  allocate(fjac(size(x), size(x)))
+
+  ! Compute block decomposition
+  nullify(x_indices, f_indices, x_all)
+  call matlab_fcn(x, fvec, fjac)
+  call dm_blocks(fjac, blocks)
+
+  if (debug) then
+     write (debug_msg, "('DYNARE_SOLVE (solve_algo=13|14): number of blocks = ', i0)") size(blocks)
+     call mexPrintf_trim_newline(debug_msg)
+  end if
+
+  ! Solve the system, starting from bottom-rightmost block
+  do i = size(blocks),1,-1
+     if (debug) then
+        write (debug_msg, "('DYNARE_SOLVE (solve_algo=13|14): solving block ', i0, ' of size ', i0)") &
+             i, size(blocks(i)%col_indices)
+        call mexPrintf_trim_newline(debug_msg)
+     end if
+
+     if (specializedunivariateblocks .and. size(blocks(i)%col_indices) == 1) then
+        if (debug) then
+           write (debug_msg, "('DYNARE_SOLVE (solve_algo=13|14): solving block ', i0, ' by evaluating RHS')") i
+           call mexPrintf_trim_newline(debug_msg)
+        end if
+        associate (eq => blocks(i)%row_indices(1), var => blocks(i)%col_indices(1))
+          if (fre .or. any(abs(fjac(eq, evaled_cols)) > 0._real64)) then
+             ! Reevaluation of the residuals is required because the current RHS depends on
+             ! variables that potentially have been updated previously.
+             nullify(x_indices, f_indices, x_all)
+             call matlab_fcn(x, fvec)
+             deallocate(evaled_cols) ! This shouldn’t be necessary, but it crashes otherwise with gfortran 8
+             allocate(evaled_cols(0))
+             fre = .false.
+          end if
+          evaled_cols = [ evaled_cols, var]
+          block
+            ! An associate() construct for lhs_eq and endo_name_var makes the
+            ! code crash (with double free) using gfortran 8. Hence use a block
+            character(kind=c_char, len=:), allocatable :: lhs_eq, endo_name_var
+            lhs_eq = mxArrayToString(mxGetCell(lhs, int(eq, mwIndex)))
+            endo_name_var = mxArrayToString(mxGetCell(endo_names, int(var, mwIndex)))
+            if (lhs_eq == endo_name_var .or. lhs_eq == "log(" // endo_name_var // ")") then
+               if (isloggedlhs(eq)) then
+                  x(var) = exp(log(x(var)) - fvec(eq))
+               else
+                  x(var) = x(var) - fvec(eq)
+               end if
+            else
+               if (debug) then
+                  write (debug_msg, "('LHS variable is not determined by RHS expression (', i0, ')')") eq
+                  call mexPrintf_trim_newline(debug_msg)
+                  write (debug_msg, "(a, ' -> ', a)") lhs_eq, endo_name_var
+                  call mexPrintf_trim_newline(debug_msg)
+               end if
+               if (lhs_eq(1:9) == "AUX_DIFF_" .or. lhs_eq(1:13) == "log(AUX_DIFF_") then
+                  if (isauxdiffloggedrhs(eq)) then
+                     x(var) = exp(log(x(var)) + fvec(eq))
+                  else
+                     x(var) = x(var) + fvec(eq)
+                  end if
+               else
+                  call mexErrMsgTxt("Algorithm solve_algo=14 cannot be used with this nonlinear problem")
+                  return
+               end if
+            end if
+          end block
+        end associate
+        cycle
+     else
+        if (debug) then
+           write (debug_msg, "('DYNARE_SOLVE (solve_algo=13|14): solving block ', i0, ' with trust region routine')") i
+           call mexPrintf_trim_newline(debug_msg)
+        end if
+     end if
+
+     block
+       real(real64), dimension(size(blocks(i)%col_indices)) :: x_block
+       x_indices => blocks(i)%col_indices
+       f_indices => blocks(i)%row_indices
+       x_all => x
+       if (size(x_indices) /= size(f_indices)) then
+          call mexErrMsgTxt("Non-square block")
+          return
+       end if
+       x_block = x(x_indices)
+       call trust_region_solve(x_block, matlab_fcn, info, tolx, tolf, maxiter)
+       x(x_indices) = x_block
+     end block
+
+     fre = .true.
+  end do
+
+  ! Verify that we have a solution
+  ! Note that here we use the ∞-norm, while trust region uses 2-norm; otherwise
+  ! this check would almost always fail (because the 2-norm of the full fvec is
+  ! larger than the 2-norm of its sub-vectors)
+  ! If the check fails, this normally means that the block decomposition was
+  ! incorrect (because some element of the Jacobian was numerically zero at the
+  ! guess value while not being symbolically zero)
+  nullify(x_indices, f_indices, x_all)
+  call matlab_fcn(x, fvec)
+  if (maxval(abs(fvec)) > tolf) then
+     if (debug) &
+          call mexPrintf_trim_newline("DYNARE_SOLVE (solve_algo=13|14): residuals still too large, solving for the whole model")
+     call trust_region_solve(x, matlab_fcn, info, tolx, tolf, maxiter)
+  else
+     info = 1
+  end if
+
+  plhs(1) = mxCreateDoubleMatrix(int(size(x, 1), mwSize), 1_mwSize, mxREAL)
+  mxGetPr(plhs(1)) = x
+  if (info == 1) then
+     plhs(2) = mxCreateDoubleScalar(0._c_double)
+  else
+     plhs(2) = mxCreateDoubleScalar(1._c_double)
+  end if
+end subroutine mexFunction
diff --git a/mex/sources/block_trust_region/test/Makefile b/mex/sources/block_trust_region/test/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..8bc71c7c0927cd9082548285fcc00660d849e920
--- /dev/null
+++ b/mex/sources/block_trust_region/test/Makefile
@@ -0,0 +1,34 @@
+FC = gfortran
+FCFLAGS = -g -Wall
+
+all: dulmage_mendelsohn_test trust_region_test
+
+dulmage_mendelsohn_test: dulmage_mendelsohn.o dulmage_mendelsohn_test.o
+	$(FC) $(FCFLAGS) $^ -o $@
+
+dulmage_mendelsohn_test.o: dulmage_mendelsohn_test.f08 dulmage_mendelsohn.mod
+	$(FC) $(FCFLAGS) -c $< -o $@
+
+dulmage_mendelsohn.mod: dulmage_mendelsohn.o
+
+dulmage_mendelsohn.o: ../dulmage_mendelsohn.f08
+	$(FC) $(FCFLAGS) -c $< -o $@
+
+trust_region_test: trust_region.o trust_region_test.o
+	$(FC) $(FCFLAGS) $^ -o $@ -llapack -lblas
+
+trust_region_test.o: trust_region_test.f08 trust_region.mod
+	$(FC) $(FCFLAGS) -c $< -o $@
+
+trust_region.mod: trust_region.o
+
+trust_region.o: ../trust_region.f08 lapack.mod
+	$(FC) $(FCFLAGS) -c $< -o $@
+
+blas_lapack.o: ../../blas_lapack.F08
+	$(FC) $(FCFLAGS) -c $< -o $@
+
+lapack.mod: blas_lapack.o
+
+clean:
+	rm -f *.o *.mod dulmage_mendelsohn_test trust_region_test
diff --git a/mex/sources/block_trust_region/test/dulmage_mendelsohn_test.f08 b/mex/sources/block_trust_region/test/dulmage_mendelsohn_test.f08
new file mode 100644
index 0000000000000000000000000000000000000000..43c7f428cb36c6e1ebb0fd2cd053454cf77e25b2
--- /dev/null
+++ b/mex/sources/block_trust_region/test/dulmage_mendelsohn_test.f08
@@ -0,0 +1,63 @@
+program dmperm_test
+  use iso_fortran_env
+  use dulmage_mendelsohn
+  implicit none
+
+  real(real64), dimension(12, 11) :: M
+  integer, dimension(size(M, 1)) :: row_order
+  integer, dimension(size(M, 2)) :: col_order
+  integer, dimension(:), allocatable :: row_blocks, col_blocks
+  type(dm_block), dimension(:), allocatable :: blocks
+  integer :: i, j
+
+  ! Matrix given p. 305 of Pothen and Fan (1990)
+  M = reshape(real([ &
+       1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, &
+       0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, &
+       1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, &
+       0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, &
+       0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, &
+       0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, &
+       0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, &
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, &
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, &
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, &
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, &
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1  &
+       ], real64), shape(M), order = [2, 1])
+
+  ! Shuffle the matrix
+  M = M([ 3, 9, 8, 7, 1, 2, 5, 4, 10, 12, 11, 6 ], &
+        [ 5, 9, 6, 1, 10, 8, 4, 11, 2, 7, 3 ])
+
+  print *, "Shuffled matrix:"
+  do i = 1, size(M, 1)
+     write (*, "(11f3.0) ") (M(i, j), j=1,size(M,2))
+  end do
+  print *
+
+  ! Test dmperm
+  call dmperm(M, row_order, col_order, row_blocks, col_blocks)
+
+  print *, "Reordered matrix:"
+  do i = 1, size(M, 1)
+     write (*, "(11f3.0) ") (M(row_order(i), col_order(j)), j=1,size(M,2))
+  end do
+  print *
+
+  ! Print fine decomposition
+  print *, "Column blocks:", col_blocks
+  print *, "Row blocks:", row_blocks
+  print *
+
+  ! Test compute_dm_blocks
+  call dm_blocks(M, blocks)
+  do i = 1, size(blocks)
+     print *, "*** Block:", i
+     print *, "Coarse type: ", blocks(i)%coarse_type
+     print *, "Rows:", blocks(i)%row_indices
+     print *, "Columns:", blocks(i)%col_indices
+     print *, "Predecessors:", blocks(i)%predecessors
+     print *
+  end do
+end program dmperm_test
diff --git a/mex/sources/block_trust_region/test/trust_region_test.f08 b/mex/sources/block_trust_region/test/trust_region_test.f08
new file mode 100644
index 0000000000000000000000000000000000000000..8ec263b05df5ec204ff39c4427c1711f09d51086
--- /dev/null
+++ b/mex/sources/block_trust_region/test/trust_region_test.f08
@@ -0,0 +1,63 @@
+program trust_region_test
+  use trust_region
+  use iso_fortran_env
+  implicit none
+
+  real(real64), dimension(2), parameter :: rosenbrock_guess = [ -10**4, 1 ]
+  real(real64), dimension(2), parameter :: rosenbrock_solution = [ 1, 1 ]
+  real(real64), dimension(2) :: rosenbrock_x
+
+  real(real64), dimension(4), parameter :: powell1_guess = [ 3, -1, 0, 1 ]
+  real(real64), dimension(4), parameter :: powell1_solution = 0
+  real(real64), dimension(4) :: powell1_x
+
+  integer :: info
+
+  rosenbrock_x = rosenbrock_guess
+  call trust_region_solve(rosenbrock_x, rosenbrock, info)
+  if (info /= 1 .or. maxval(abs(rosenbrock_x - rosenbrock_solution)) > 1e-11_real64) &
+       error stop "Failed to solve rosenbrock"
+
+  powell1_x = powell1_guess
+  call trust_region_solve(powell1_x, powell1, info, tolf = 1e-8_real64)
+  if (info /= 1 .or. maxval(abs(rosenbrock_x - rosenbrock_solution)) > 4e-5_real64) &
+       error stop "Failed to solve powell1"
+contains
+  subroutine rosenbrock(x, fvec, fjac)
+    real(real64), dimension(:), intent(in) :: x
+    real(real64), dimension(size(x)), intent(out) :: fvec
+    real(real64), dimension(size(x),size(x)), intent(out), optional :: fjac
+
+    fvec(1) = 1 - x(1)
+    fvec(2) = 10*(x(2)-x(1)**2)
+
+    if (present(fjac)) then
+       fjac(1,1) = -1
+       fjac(1,2) = 0
+       fjac(2,1) = -20*x(1)
+       fjac(2,2) = 10
+    end if
+  end subroutine rosenbrock
+
+  subroutine powell1(x, fvec, fjac)
+    real(real64), dimension(:), intent(in) :: x
+    real(real64), dimension(size(x)), intent(out) :: fvec
+    real(real64), dimension(size(x),size(x)), intent(out), optional :: fjac
+
+    fvec(1) = x(1)+10*x(2)
+    fvec(2) = sqrt(5._real64)*(x(3)-x(4))
+    fvec(3) = (x(2)-2*x(3))**2
+    fvec(4) = sqrt(10._real64)*(x(1)-x(4))**2
+
+    if (present(fjac)) then
+       fjac(1,1) = 1
+       fjac(1,2) = 10
+       fjac(2,3) = sqrt(5._real64)
+       fjac(2,4) = -fjac(2,3)
+       fjac(3,2) = 2*(x(2)-2*x(3))
+       fjac(3,3) = -2*fjac(3,2)
+       fjac(4,1) = 2*sqrt(10._real64)*(x(1)-x(4))
+       fjac(4,4) = -fjac(4,1)
+    end if
+  end subroutine powell1
+end program trust_region_test
diff --git a/mex/sources/block_trust_region/trust_region.f08 b/mex/sources/block_trust_region/trust_region.f08
new file mode 100644
index 0000000000000000000000000000000000000000..84e0f1c6cb06a67c9b6710f65e1ab5b8fce46b5b
--- /dev/null
+++ b/mex/sources/block_trust_region/trust_region.f08
@@ -0,0 +1,300 @@
+! Solves a system of nonlinear equation with the trust region method
+!
+! Implementation heavily inspired from the hybrj function from MINPACK
+
+! Copyright © 2019 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/>.
+
+module trust_region
+  use iso_fortran_env
+  use lapack
+  implicit none
+
+  private
+  public :: trust_region_solve
+
+contains
+  subroutine trust_region_solve(x, f, info, tolx, tolf, maxiter)
+
+    real(real64), dimension(:), intent(inout) :: x ! On entry: guess value; on exit: solution
+    interface
+       subroutine f(x1, fvec, fjac)
+         use iso_fortran_env
+         real(real64), dimension(:), intent(in) :: x1
+         real(real64), dimension(size(x)), intent(out) :: fvec
+         real(real64), dimension(size(x),size(x)), intent(out), optional :: fjac
+       end subroutine f
+    end interface
+    ! Exit code:
+    !  1 = success (relative error between two consecutive iterates is at most tolx)
+    !  2 = maximum number of iterations reached
+    !  3 = tolx is too small, no further improvement of the approximate solution x is possible
+    !  4 = iteration is not making good progress, as measured by the improvement from the last maxslowiter iterations
+    integer, intent(out) :: info
+    real(real64), intent(in), optional :: tolx, tolf ! Tolerances in x and f
+    integer, intent(in), optional :: maxiter ! Maximum number of iterations
+
+    real(real64) :: tolx_actual, tolf_actual
+    integer :: maxiter_actual
+    integer, parameter :: maxslowiter = 15 ! Maximum number of consecutive iterations with slow progress
+    real(real64), parameter :: macheps = epsilon(x)
+    real(real64) :: delta ! Radius of the trust region
+    real(real64), dimension(size(x)) :: fvec ! Current function value
+    real(real64) :: fn ! Norm of the current function value
+    real(real64), dimension(size(x)) :: jcn, dg ! Jacobian column-norms and rescaling factors
+    real(real64), dimension(size(x), size(x)) :: fjac ! Jacobian matrix
+    real(real64), dimension(size(x)) :: gn ! Gauss-Newton direction
+    logical :: recompute_gn ! Whether to recompute Gauss-Newton direction at next dogleg
+    integer :: niter ! Current iteration
+    integer :: ncsucc ! Number of consecutive successful iterations
+    integer :: ncslow ! Number of consecutive iterations with slow progress
+
+    ! Initialize variables associated to optional arguments
+    if (present(tolx)) then
+       tolx_actual = tolx
+    else
+       tolx_actual = 1e-6_real64
+    end if
+    if (present(tolf)) then
+       tolf_actual = tolf
+    else
+       tolf_actual = 1e-6_real64
+    end if
+    if (present(maxiter)) then
+       maxiter_actual = maxiter
+    else
+       maxiter_actual = 50
+    end if
+
+    niter = 1
+    ncsucc = 0
+    ncslow = 0
+    info = 0
+
+    ! Initial function evaluation
+    call f_and_update_norms
+
+    do
+       ! Compute scaling factors
+       if (niter == 1) then
+          where (jcn /= 0)
+             dg = jcn
+          elsewhere
+             dg = 1
+          end where
+       else
+          ! Rescale adaptatively
+          ! MINPACK uses dg=max(dg, jcn), but this means that scale factors
+          ! will never decrease, which can be bad if the Jacobian at initial
+          ! guess has large columns that later decrease
+          dg = max(0.1_real64 * dg, jcn)
+       end if
+
+       block
+         ! Declare variables that are not kept across iterations
+         real(real64) :: xnorm ! Norm of rescaled x
+         real(real64), dimension(size(x)) :: p ! Candidate increment computed by dogleg
+         real(real64) :: pnorm ! Norm of rescaled p
+         real(real64), dimension(size(x)) :: x2 ! Candidate x for next iteration
+         real(real64), dimension(size(x)) :: fvec2 ! Candidate function values
+         real(real64) :: fn2 ! Norm of the candidate function values
+         real(real64), dimension(size(x)) :: w ! Candidate in the approximated linear model
+         real(real64) :: actred, prered, ratio ! Actual and predicted reduction, and their ratio
+
+         xnorm = norm2(dg * x)
+
+         if (niter == 1) then
+            if (xnorm > 0) then
+               delta = xnorm
+            else
+               delta = 1
+            end if
+         end if
+
+         ! Get trust-region model (dogleg) minimizer
+         call dogleg(fjac, fvec, dg, delta, p, gn, recompute_gn)
+         recompute_gn = .false.
+         p = -p
+         pnorm = norm2(dg * p)
+
+         ! Compute candidate point x2 and function value there
+         x2 = x + p
+         call f(x2, fvec2)
+         fn2 = norm2(fvec2)
+
+         ! Actual reduction
+         if (fn2 < fn) then
+            actred = 1 - (fn2/fn)**2
+         else
+            actred = -1
+         end if
+
+         ! Predicted reduction
+         ! Could be replaced by t => norm2(fvec + matmul(fjac, p))
+         ! First, compute w = fvec + fjac·p
+         associate (n => int(size(x), blint))
+           w = fvec
+           call dgemv("N", n, n, 1._real64, fjac, n, p, 1_blint, 1._real64, w, 1_blint)
+         end associate
+         associate (t => norm2(w))
+           if (t < fn) then
+              prered = 1 - (t/fn)**2
+           else
+              prered = 0
+           end if
+         end associate
+
+         ! Ratio
+         if (prered > 0) then
+            ratio = actred / prered
+         else
+            ratio = 0
+         end if
+
+         ! Update delta
+         if (niter == 1) delta = min(delta, pnorm) ! On 1st iteration, adjust radius
+         if (ratio < 0.1_real64) then ! Failed iteration
+            delta = delta / 2
+            ncsucc = 0
+         else ! Successful iteration
+            ncsucc = ncsucc + 1
+            if (abs(1-ratio) <= 0.1_real64) then
+               delta = 2*pnorm
+            else if (ratio >= 0.5_real64 .or. ncsucc > 1) then
+               delta = max(delta, 2*pnorm)
+            end if
+         end if
+
+         ! If successful iteration, move x and update various variables
+         if (ratio >= 1e-4_real64) then
+            x = x2
+            call f_and_update_norms
+            xnorm = norm2(dg * x)
+         end if
+
+         ! Determine progress of the iteration
+         ncslow = ncslow + 1
+         if (actred >= 0.001_real64) ncslow = 0
+
+         ! Increment iteration counter and exit if maximum reached
+         niter = niter + 1
+         if (niter == maxiter_actual) info = 2
+
+         ! Test for convergence
+         if (delta <= tolx_actual*xnorm .or. fn <= tolf_actual) info = 1
+
+         ! Tests for termination and stringent tolerances
+         if (max(0.1_real64*delta, pnorm) <= 10*epsilon(xnorm)*xnorm) info = 3
+         if (ncslow == maxslowiter) info = 4
+       end block
+
+       if (info /= 0) exit
+    end do
+  contains
+    ! Given x, updates fvec, fjac, fn and jcn
+    subroutine f_and_update_norms
+      integer :: i
+
+      call f(x, fvec, fjac)
+      recompute_gn = .true.
+      fn = norm2(fvec)
+      do i = 1, size(jcn)
+         jcn(i) = norm2(fjac(:, i))
+      end do
+    end subroutine f_and_update_norms
+  end subroutine trust_region_solve
+
+  ! Solve the double dogleg trust-region least-squares problem:
+  ! Minimize ‖r·x−b‖₂ subject to the constraint ‖d.*x‖ ≤ delta (where “.*”
+  ! designates element-by-element multiplication),
+  ! x is a convex combination of the Gauss-Newton and scaled gradient
+  subroutine dogleg(r, b, d, delta, x, gn, recompute_gn)
+    real(real64), dimension(:), intent(in) :: b, d
+    real(real64), dimension(:,:), intent(in) :: r
+    real(real64), intent(in) :: delta ! Radius of the trust region
+    real(real64), dimension(:), intent(out) :: x ! Solution of the problem
+    real(real64), dimension(:), intent(inout) :: gn ! Gauss-Newton direction
+    logical, intent(in) :: recompute_gn ! Whether to re-compute Gauss-Newton direction
+
+    integer(blint) :: n
+
+    n = size(x)
+    if (size(b) /= n .or. size(d) /= n .or. size(r, 1) /= n .or. size(r, 2) /= n) &
+         error stop "Inconsistent dimensions"
+
+    ! Compute Gauss-Newton direction: gn = r⁻¹·b
+    if (recompute_gn) then
+       block
+         real(real64), dimension(size(x), size(x)) :: r_plu
+         integer(blint), dimension(size(x)) :: ipiv
+         integer(blint) :: info
+         gn = b
+         r_plu = r
+         call dgesv(n, 1_blint, r_plu, n, ipiv, gn, n, info)
+         ! TODO: use same trick as NLSolve.jl in case of singularity
+         if (info /= 0) error stop "LAPACK dgesv error"
+       end block
+    end if
+
+    associate (xn => norm2(d*gn))
+      if (xn <= delta) then
+         x = gn
+      else
+         ! Gauss-Newton direction is too big, get scaled gradient
+         block
+           real(real64), dimension(size(x)) :: s, t
+           real(real64) :: snm, alpha
+
+           ! s = rᵀ·b ./ d
+           ! Alternatively, could use: s = matmul(transpose(r), b) / d
+           call dgemv("T", n, n, 1._real64, r, n, b, 1_blint, 0._real64, s, 1_blint)
+           s = s / d
+           associate (sn => norm2(s))
+             if (sn > 0) then
+                ! Normalize and rescale
+                s = s / sn / d
+
+                ! Get the line minimizer in s direction
+                ! t = r·s
+                ! Alternatively, could use tn => norm2(matmul(r, s))
+                call dgemv("N", n, n, 1._real64, r, n, s, 1_blint, 0._real64, t, 1_blint)
+                associate (tn => norm2(t))
+                  snm = sn / tn**2
+                  if (snm < delta) then
+                     ! Get the dogleg path minimizer
+                     associate (bn => norm2(b), dxn => delta/xn, snmd => snm/delta)
+                       associate (tmp => (bn/sn) * (bn/xn) * snmd)
+                         alpha = dxn*(1-snmd**2) / (tmp - dxn*snmd**2 + &
+                              sqrt((tmp-dxn)**2 + (1-dxn**2)*(1-snmd**2)))
+                       end associate
+                     end associate
+                  else
+                     alpha = 0
+                  end if
+                end associate
+             else
+                alpha = delta / xn
+                snm = 0
+             end if
+           end associate
+
+           x = alpha * gn + ((1-alpha) * min(snm, delta)) * s
+         end block
+      end if
+    end associate
+  end subroutine dogleg
+end module trust_region
diff --git a/tests/.gitignore b/tests/.gitignore
index 275d8736e94b9035f21f0e54738f55cc04d1cd29..7b5c438826aa63ae6af5d7cbf06ab5aa013605b8 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -96,6 +96,9 @@ wsOct
 !/kronecker/test_kron.m
 !/load_octave_packages.m
 !/ls2003/data_ca1.m
+!/matrix_notation/extFunNoDerivsMatrix.m
+!/matrix_notation/extFunFirstDerivMatrix.m
+!/matrix_notation/extFunWithFirstAndSecondDerivsMatrix.m
 !/measurement_errors/data_ca1.m
 !/measurement_errors/fs2000_corr_me_ml_mcmc/fsdat_simul.m
 !/missing/simulate_data_with_missing_observations.m
@@ -161,3 +164,8 @@ wsOct
 !/shock_decomposition/fsdat_simul.m
 !/smoother2histval/fsdat_simul.m
 !/steady_state/walsh1_old_ss_steadystate.m
+
+/pac/var-6/example/model/pac-expectations/*
+/pac/var-5/example/model/pac-expectations/*
+/pac/trend-component-14/example/model/pac-expectations/*
+!/ecb/aggregate/test_aggregate_routine.m
diff --git a/tests/Makefile.am b/tests/Makefile.am
index cd60e047351fb550f29463ad861d653966fb0b65..ee55632067859ee6627e93f755f5cf67b2b06b94 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -37,6 +37,7 @@ MODFILES = \
 	fs2000/fs2000.mod \
 	ls2003/ls2003_hessian_zero.mod \
 	ep/rbc.mod \
+	exogenous-observed-variables/preprocessor.mod \
 	estimation/fs2000_with_weibull_prior.mod \
 	estimation/fs2000_initialize_from_calib.mod	\
 	estimation/fs2000_estimated_params_init.mod	\
@@ -127,6 +128,7 @@ MODFILES = \
 	histval_initval_file/sim_exo_lead_lag_initvalf.mod \
         ramst_normcdf_and_friends.mod \
 	ramst_vec.mod \
+	ramst_mshocks_vec.mod \
 	example1_varexo_det.mod \
 	predetermined_variables.mod \
 	fs2000_ssfile.mod \
@@ -145,6 +147,7 @@ MODFILES = \
 	steady_state/walsh1_ssm_block.mod \
 	steady_state/multi_leads.mod \
 	steady_state/example1_trust_region.mod \
+	steady_state/example1_block_trust_region.mod \
 	steady_state/Gali_2015_chapter_6_4.mod \
 	steady_state_operator/standard.mod \
 	steady_state_operator/use_dll.mod \
@@ -354,6 +357,7 @@ MODFILES = \
 	shock_decomposition/fs2000_est_varlist.mod \
 	shock_decomposition/fs2000_cal_groups.mod \
 	shock_decomposition/ls2003_plot.mod \
+	shock_decomposition/shock_decomposition_backward.mod \
 	stochastic_purely_forward/stochastic_purely_forward.mod \
 	stochastic_purely_forward/stochastic_purely_forward_with_static.mod \
 	forecast/Hansen_exo_det_forecast.mod \
@@ -412,7 +416,143 @@ MODFILES = \
 	bgp/nk-1/nk.mod \
 	bgp/ramsey-1/ramsey.mod \
 	dynare-command-options/ramst.mod \
-	particle/local_state_space_iteration_k_test.mod
+	particle/local_state_space_iteration_k_test.mod \
+	matrix_notation/deterministic_matrix.mod \
+	matrix_notation/deterministic_scalar.mod \
+	matrix_notation/stochastic_matrix.mod \
+	matrix_notation/stochastic_scalar.mod \
+	matrix_notation/benchmark.mod \
+	matrix_notation/no_deriv_given_matrix_dll.mod \
+	matrix_notation/no_deriv_given_matrix.mod \
+	matrix_notation/first_deriv_given_matrix_dll.mod \
+	matrix_notation/first_deriv_given_matrix.mod \
+	matrix_notation/first_and_2nd_deriv_given_matrix_dll.mod \
+	matrix_notation/first_and_2nd_deriv_given_matrix.mod
+
+ECB_MODFILES = \
+	var-expectations/1/example.mod \
+	var-expectations/2/example.mod \
+	var-expectations/3/example.mod \
+	var-expectations/4/example.mod \
+	var-expectations/5/example.mod \
+	var-expectations/6/example.mod \
+	var-expectations/6/substitution.mod \
+	var-expectations/7/example.mod \
+	var-expectations/7/substitution.mod \
+	var-expectations/8/example.mod \
+	var-expectations/8/substitution.mod \
+	var-expectations/9/example.mod \
+	var-expectations/10/example.mod \
+	trend-component-and-var-models/vm1.mod \
+	trend-component-and-var-models/vm2.mod \
+	trend-component-and-var-models/vm3.mod \
+	trend-component-and-var-models/vm4.mod \
+	trend-component-and-var-models/vm5.mod \
+	trend-component-and-var-models/tcm1.mod \
+	trend-component-and-var-models/tcm2.mod \
+	trend-component-and-var-models/tcm3.mod \
+	trend-component-and-var-models/tcm4.mod \
+	trend-component-and-var-models/tcm5.mod \
+	trend-component-and-var-models/tcm6.mod \
+	trend-component-and-var-models/tcm7.mod \
+	trend-component-and-var-models/tcm8.mod \
+	trend-component-and-var-models/tcm9.mod \
+	trend-component-and-var-models/tcm10.mod \
+	trend-component-and-var-models/tcm11.mod \
+	trend-component-and-var-models/tcm12.mod \
+	trend-component-and-var-models/legacy/vm1.mod \
+	trend-component-and-var-models/legacy/vm2.mod \
+	trend-component-and-var-models/legacy/vm3.mod \
+	trend-component-and-var-models/legacy/tcm1.mod \
+	trend-component-and-var-models/legacy/tcm2.mod \
+	trend-component-and-var-models/legacy/tcm3.mod \
+	trend-component-and-var-models/legacy/tcm4.mod \
+	trend-component-and-var-models/legacy/tcm5.mod \
+	pac/var-1/example.mod \
+	pac/var-2/example.mod \
+	pac/var-3/example.mod \
+	pac/var-4/example.mod \
+	pac/var-5/example.mod \
+	pac/var-5/substitution.mod \
+	pac/var-6/example.mod \
+	pac/var-6/substitution.mod \
+	pac/trend-component-1/example.mod \
+	pac/trend-component-2/example.mod \
+	pac/trend-component-3/example.mod \
+	pac/trend-component-4/example.mod \
+	pac/trend-component-5/example.mod \
+	pac/trend-component-6/example.mod \
+	pac/trend-component-7/example.mod \
+	pac/trend-component-9/example.mod \
+	pac/trend-component-10/example.mod \
+	pac/trend-component-11/example.mod \
+	pac/trend-component-12/example.mod \
+	pac/trend-component-13a/example.mod \
+	pac/trend-component-13b/example.mod \
+	pac/trend-component-14/example.mod \
+	pac/trend-component-14/substitution.mod \
+	pac/trend-component-15/example.mod \
+	pac/trend-component-16/example.mod \
+	pac/trend-component-17/example.mod \
+	pac/trend-component-18/example.mod \
+	pac/trend-component-19/example1.mod \
+	pac/trend-component-19/example2.mod \
+	pac/trend-component-19/example3.mod \
+	pac/trend-component-19-growth-lin-comb/example.mod \
+	pac/trend-component-1-mce/example_det.mod \
+	pac/trend-component-1-mce/example_sto.mod \
+	pac/trend-component-2-mce/example_det.mod \
+	pac/trend-component-2-mce/example_sto.mod \
+	pac/trend-component-20-1/example.mod \
+	pac/trend-component-20-2/example.mod \
+	pac/trend-component-20-3/example.mod \
+	pac/trend-component-20-4/example.mod \
+	pac/trend-component-21/example.mod \
+	pac/trend-component-22/example.mod \
+	pac/trend-component-23/example.mod \
+	pac/trend-component-24/example.mod \
+	pac/trend-component-25/example.mod \
+	pac/trend-component-26/example.mod \
+	pac/trend-component-27/example.mod \
+	pac/trend-component-28/example1.mod \
+	pac/trend-component-28/example2.mod \
+	pac/trend-component-28/example3.mod \
+	pac/trend-component-28/example4.mod \
+	pac/trend-component-28/example5.mod \
+	pac/trend-component-28/example6.mod \
+	pac/trend-component-29/example2.mod \
+	pac/trend-component-29/example2.mod \
+	pac/trend-component-30/example.mod \
+	write/example1.mod \
+	ecb/backward-models/irf/solow_1.mod \
+	ecb/backward-models/irf/solow_2.mod \
+	ecb/cherrypick/test1.mod \
+	ecb/cherrypick/test2.mod \
+	ecb/contribution-plots/contrib1.mod \
+	ecb/contribution-plots/contrib2.mod
+
+OLS_MODFILES = \
+	estimation/univariate/bayesian.mod \
+	estimation/univariate/bayesian_param_names.mod \
+	ecb/SURGibbs/fulton_fish.mod \
+	estimation/univariate/ols/ols_wc_1.mod \
+	estimation/univariate/ols/ols_wc_2.mod \
+	estimation/univariate/ols/ols_wc_3.mod \
+	estimation/univariate/ols/ols_date_range.mod \
+	estimation/univariate/ols/ols_param_names.mod \
+	estimation/univariate/ols/ols.mod \
+	ecb/SUR/sur_noniterative.mod \
+	ecb/SUR/sur_params_noniterative.mod \
+	ecb/SUR/panel_var_diff_NB_simulation_test.mod \
+	ecb/SUR/panel_var_diff_NB_simulation_zero_eq.mod \
+	ecb/pooled_ols/panel_var_diff_NB_simulation_test.mod \
+	ecb/pooled_ols/test_param_names.mod \
+	ecb/pooled_fgls/panel_var_diff_NB_simulation_test.mod \
+	ecb/pooled_fgls/test_param_names.mod
+
+ECB_MODFILES += $(OLS_MODFILES)
+
+MODFILES += $(ECB_MODFILES)
 
 PARTICLEFILES = \
 	particle/dsge_base2.mod \
@@ -647,14 +787,53 @@ kalman/likelihood_from_dynare/fs2000ns_uncorr_ME_missing.o.trs: kalman/likelihoo
 kalman/likelihood_from_dynare/fs2000ns_corr_ME_missing.m.trs: kalman/likelihood_from_dynare/fs2000ns_uncorr_ME.m.trs
 kalman/likelihood_from_dynare/fs2000ns_corr_ME_missing.o.trs: kalman/likelihood_from_dynare/fs2000ns_uncorr_ME.o.trs
 
+var-expectations/6/substitution.m.trs: var-expectations/6/example.m.trs
+var-expectations/6/substitution.o.trs: var-expectations/6/example.o.trs
+var-expectations/7/substitution.m.trs: var-expectations/7/example.m.trs
+var-expectations/7/substitution.o.trs: var-expectations/7/example.o.trs
+var-expectations/8/substitution.m.trs: var-expectations/8/example.m.trs
+var-expectations/8/substitution.o.trs: var-expectations/8/example.o.trs
+
+pac/var-5/substitution.m.trs: pac/var-5/example.m.trs
+pac/var-5/substitution.o.trs: pac/var-5/example.o.trs
+pac/var-6/substitution.m.trs: pac/var-6/example.m.trs
+pac/var-6/substitution.o.trs: pac/var-6/example.o.trs
+pac/trend-component-14/substitution.m.trs: pac/trend-component-14/example.m.trs
+pac/trend-component-14/substitution.o.trs: pac/trend-component-14/example.o.trs
+
 lmmcp/sw_newton.m.trs: lmmcp/sw_lmmcp.m.trs
 lmmcp/sw_newton.o.trs: lmmcp/sw_lmmcp.o.trs
 
+var-expectations/4/example.m.trs: var-expectations/3/example.m.trs
+var-expectations/4/example.o.trs: var-expectations/3/example.o.trs
+
+trend-component-and-var-models/tcm7.m.trs: trend-component-and-var-models/tcm6.m.trs
+trend-component-and-var-models/tcm7.o.trs: trend-component-and-var-models/tcm6.o.trs
+trend-component-and-var-models/tcm8.m.trs: trend-component-and-var-models/tcm6.m.trs
+trend-component-and-var-models/tcm8.o.trs: trend-component-and-var-models/tcm6.o.trs
+
 discretionary_policy/dennis_1_estim.m.trs: discretionary_policy/dennis_1.m.trs
 discretionary_policy/dennis_1_estim.o.trs: discretionary_policy/dennis_1.o.trs
 discretionary_policy/Gali_2015_chapter_3_nonlinear.m.trs: discretionary_policy/Gali_2015_chapter_3.m.trs
 discretionary_policy/Gali_2015_chapter_3_nonlinear.o.trs: discretionary_policy/Gali_2015_chapter_3.o.trs
 
+matrix_notation/deterministic_scalar.m.trs: matrix_notation/deterministic_matrix.m.trs
+matrix_notation/deterministic_scalar.o.trs: matrix_notation/deterministic_matrix.o.trs
+matrix_notation/stochastic_scalar.m.trs: matrix_notation/stochastic_matrix.m.trs
+matrix_notation/stochastic_scalar.o.trs: matrix_notation/stochastic_matrix.o.trs
+matrix_notation/first_deriv_given_matrix.m.trs: matrix_notation/benchmark.m.trs
+matrix_notation/first_deriv_given_matrix.o.trs: matrix_notation/benchmark.o.trs
+matrix_notation/first_deriv_given_matrix_dll.m.trs: matrix_notation/benchmark.m.trs
+matrix_notation/first_deriv_given_matrix_dll.o.trs: matrix_notation/benchmark.o.trs
+matrix_notation/first_and_2nd_deriv_given_matrix.m.trs: matrix_notation/benchmark.m.trs
+matrix_notation/first_and_2nd_deriv_given_matrix.o.trs: matrix_notation/benchmark.o.trs
+matrix_notation/first_and_2nd_deriv_given_matrix_dll.m.trs: matrix_notation/benchmark.m.trs
+matrix_notation/first_and_2nd_deriv_given_matrix_dll.o.trs: matrix_notation/benchmark.o.trs
+matrix_notation/no_deriv_given_matrix.m.trs: matrix_notation/benchmark.m.trs
+matrix_notation/no_deriv_given_matrix.o.trs: matrix_notation/benchmark.o.trs
+matrix_notation/no_deriv_given_matrix_dll.m.trs: matrix_notation/benchmark.m.trs
+matrix_notation/no_deriv_given_matrix_dll.o.trs: matrix_notation/benchmark.o.trs
+
 observation_trends_and_prefiltering/MCMC: m/observation_trends_and_prefiltering/MCMC o/observation_trends_and_prefiltering/MCMC
 m/observation_trends_and_prefiltering/MCMC: $(patsubst %.mod, %.m.trs, $(filter observation_trends_and_prefiltering/MCMC/%.mod, $(MODFILES)))
 o/observation_trends_and_prefiltering/MCMC: $(patsubst %.mod, %.o.trs, $(filter observation_trends_and_prefiltering/MCMC/%.mod, $(MODFILES)))
@@ -835,6 +1014,22 @@ gradient: m/gradient o/gradient
 m/gradient: $(patsubst %.mod, %.m.trs, $(filter gradient/%.mod, $(MODFILES)))
 o/gradient: $(patsubst %.mod, %.o.trs, $(filter gradient/%.mod, $(MODFILES)))
 
+var-expectations: m/var-expectations o/var-expectations
+m/var-expectations: $(patsubst %.mod, %.m.trs, $(filter var-expectations/%.mod, $(MODFILES)))
+o/var-expectations: $(patsubst %.mod, %.o.trs, $(filter var-expectations/%.mod, $(MODFILES)))
+
+estimation/univariate/ols: m/estimation/univariate/ols o/estimation/univariate/ols
+m/estimation/univariate/ols: $(patsubst %.mod, %.m.trs, $(filter estimation/univariate/ols/%.mod, $(MODFILES)))
+o/estimation/univariate/ols: $(patsubst %.mod, %.o.trs, $(filter estimation/univariate/ols/%.mod, $(MODFILES)))
+
+trend-component-and-var-models: m/trend-component-and-var-models o/trend-component-and-var-models
+m/trend-component-and-var-models: $(patsubst %.mod, %.m.trs, $(filter trend-component-and-var-models/%.mod, $(MODFILES)))
+o/trend-component-and-var-models: $(patsubst %.mod, %.o.trs, $(filter trend-component-and-var-models/%.mod, $(MODFILES)))
+
+pac: m/pac o/pac
+m/pac: $(patsubst %.mod, %.m.trs, $(filter pac/%.mod, $(MODFILES)))
+o/pac: $(patsubst %.mod, %.o.trs, $(filter pac/%.mod, $(MODFILES)))
+
 particle: m/particle o/particle
 m/particle: $(patsubst %.mod, %.m.trs, $(PARTICLEFILES))
 o/particle: $(patsubst %.mod, %.o.trs, $(PARTICLEFILES))
@@ -843,12 +1038,32 @@ method_of_moments: m/method_of_moments o/method_of_moments
 m/method_of_moments: $(patsubst %.mod, %.m.trs, $(filter estimation/method_of_moments/%.mod, $(MODFILES)))
 o/method_of_moments: $(patsubst %.mod, %.o.trs, $(filter estimation/method_of_moments/%.mod, $(MODFILES)))
 
+ecb: m/ecb o/ecb
+m/ecb: $(patsubst %.mod, %.m.trs, $(filter ecb/%.mod, $(MODFILES)))
+o/ecb: $(patsubst %.mod, %.o.trs, $(filter ecb/%.mod, $(MODFILES)))
+
+estimation/univariate: m/estimation/univariate o/estimation/univariate
+m/estimation/univariate: $(patsubst %.mod, %.m.trs, $(filter estimation/univariate/%.mod, $(MODFILES)))
+o/estimation/univariate: $(patsubst %.mod, %.o.trs, $(filter estimation/univariate/%.mod, $(MODFILES)))
+
+matrix_notation: m/matrix_notation o/matrix_notation
+m/matrix_notation: $(patsubst %.mod, %.m.trs, $(filter matrix_notation/%.mod, $(MODFILES)))
+o/matrix_notation: $(patsubst %.mod, %.o.trs, $(filter matrix_notation/%.mod, $(MODFILES)))
+
+# ECB files
+M_ECB_TRS_FILES = $(patsubst %.mod, %.m.trs, $(ECB_MODFILES))
+
+# Just OLS files
+M_OLS_TRS_FILES = $(patsubst %.mod, %.m.trs, $(OLS_MODFILES))
+
 # Matlab TRS Files
 M_TRS_FILES = $(patsubst %.mod, %.m.trs, $(MODFILES))
 M_TRS_FILES += 	run_block_byte_tests_matlab.m.trs \
 		run_reporting_test_matlab.m.trs \
 		run_all_unitary_tests.m.trs \
-		histval_initval_file_unit_tests.m.trs
+		histval_initval_file_unit_tests.m.trs \
+		test_aggregate_routine_1_2.m.trs \
+		test_aggregate_routine_1_2_3.m.trs
 
 M_XFAIL_TRS_FILES = $(patsubst %.mod, %.m.trs, $(XFAIL_MODFILES))
 
@@ -996,11 +1211,34 @@ EXTRA_DIST = \
 	estimation/method_of_moments/RBC/RBC_MoM_steady_helper.m \
 	estimation/method_of_moments/AFVRR/AFVRR_common.inc \
 	estimation/method_of_moments/AFVRR/AFVRR_steady_helper.m \
+	estimation/univariate/data.csv \
+	estimation/univariate/ols/mc-ols.inc \
+	ecb/SURGibbs/fishdata.csv \
+	test_aggregate_routine_1_2.m \
+	test_aggregate_routine_1_2_3.m \
+	ecb/aggregate/1/endogenous.inc \
+	ecb/aggregate/1/exogenous.inc \
+	ecb/aggregate/1/parameters.inc \
+	ecb/aggregate/1/parameter-values.inc \
+	ecb/aggregate/1/model.inc \
+	ecb/aggregate/2/endogenous.inc \
+	ecb/aggregate/2/exogenous.inc \
+	ecb/aggregate/2/parameters.inc \
+	ecb/aggregate/2/parameter-values.inc \
+	ecb/aggregate/2/model.inc \
+	ecb/aggregate/3/endogenous.inc \
+	ecb/aggregate/3/exogenous.inc \
+	ecb/aggregate/3/parameters.inc \
+	ecb/aggregate/3/parameter-values.inc \
+	ecb/aggregate/3/model.inc \
 	histval_initval_file_unit_tests.m \
 	histval_initval_file/my_assert.m \
 	histval_initval_file/ramst_data.xls \
 	histval_initval_file/ramst_data.xlsx \
-	histval_initval_file/ramst_initval_file_data.m
+	histval_initval_file/ramst_initval_file_data.m \
+	matrix_notation/extFunFirstDerivMatrix.m \
+	matrix_notation/extFunNoDerivsMatrix.m \
+	matrix_notation/extFunWithFirstAndSecondDerivsMatrix.m
 
 if ENABLE_MATLAB
 check-local: check-matlab
@@ -1016,6 +1254,12 @@ check-matlab: $(M_XFAIL_TRS_FILES) $(M_TRS_FILES)
 check-octave: $(O_XFAIL_TRS_FILES) $(O_TRS_FILES)
 	@./read_trs_files.sh "$(O_TRS_FILES)" "$(O_XFAIL_TRS_FILES)"
 
+check-matlab-ecb: $(M_ECB_TRS_FILES)
+	@./read_trs_files.sh "$(M_ECB_TRS_FILES)"
+
+check-matlab-ols: $(M_OLS_TRS_FILES)
+	@./read_trs_files.sh "$(M_OLS_TRS_FILES)"
+
 %.m.trs %.m.log: %.mod
 	@echo "`tput bold``tput setaf 8`MATLAB: $(CURDIR)/$*... `tput sgr0`"
 # The while loop is a workaround for this glibc bug: https://sourceware.org/bugzilla/show_bug.cgi?id=19329
@@ -1084,16 +1328,19 @@ check-octave: $(O_XFAIL_TRS_FILES) $(O_TRS_FILES)
 
 clean-local:
 	rm -f $(M_TRS_FILES)
+	rm -f $(M_OLS_TRS_FILES)
 	rm -f $(M_TLS_FILES)
 	rm -f $(M_XFAIL_TRS_FILES)
 	rm -f $(O_TRS_FILES)
 	rm -f $(O_TLS_FILES)
 	rm -f $(O_XFAIL_TRS_FILES)
 	rm -f $(patsubst %.trs, %.log, $(M_TRS_FILES))
+	rm -f $(patsubst %.trs, %.log, $(M_OLS_TRS_FILES))
 	rm -f $(patsubst %.trs, %.log, $(M_XFAIL_TRS_FILES))
 	rm -f $(patsubst %.trs, %.log, $(O_TRS_FILES))
 	rm -f $(patsubst %.trs, %.log, $(O_XFAIL_TRS_FILES))
 	rm -f $(patsubst %.trs, %.json, $(M_TRS_FILES))
+	rm -f $(patsubst %.trs, %.json, $(M_OLS_TRS_FILES))
 	rm -f $(patsubst %.trs, %.json, $(M_XFAIL_TRS_FILES))
 	rm -f $(patsubst %.trs, %.json, $(O_TRS_FILES))
 	rm -f $(patsubst %.trs, %.json, $(O_XFAIL_TRS_FILES))
@@ -1169,6 +1416,8 @@ clean-local:
 		k_order_perturbation/fs2000k++.jnl k_order_perturbation/fs2000k++_f.m \
 		k_order_perturbation/fs2000k++_ff.m
 
+	rm -rf ecb/cherrypick/simulation-files1 ecb/cherrypick/simulation-files2 toto.mod
+
 	rm -f discretionary_policy/dennis_simul.m
 
 	rm -f kalman/likelihood_from_dynare/fsdat_simul_corr_ME.m \
diff --git a/tests/ecb/SUR/panel_var_diff_NB_simulation_test.mod b/tests/ecb/SUR/panel_var_diff_NB_simulation_test.mod
new file mode 100644
index 0000000000000000000000000000000000000000..e5a1f85ee6bd34a813864e1a42f620f5294693ea
--- /dev/null
+++ b/tests/ecb/SUR/panel_var_diff_NB_simulation_test.mod
@@ -0,0 +1,223 @@
+// --+ options: json=compute +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_g_yer_u2_stn_L1
+de_ehic_de_ehic_L1
+
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        = DE_EHIC(-1) + res_DE_EHIC                                ;
+
+
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+NSIMS = 1;
+
+options_.noprint = 1;
+calibrated_values = M_.params;
+verbatim;
+Sigma_e = M_.Sigma_e;
+end;
+options_.bnlms.set_dynare_seed_to_default = false;
+
+nparampool = length(M_.params);
+BETA = zeros(NSIMS, nparampool);
+for i=1:NSIMS
+    firstobs = rand(3, length(M_.endo_names));
+    M_.params = calibrated_values;
+    M_.Sigma_e = Sigma_e;
+    simdata = simul_backward_model(dseries(firstobs, dates('1995Q1'), M_.endo_names), 10000);
+    simdata = simdata(simdata.dates(5001:6000));
+    names=regexp(simdata.name, 'res\w*');
+    idxs = [];
+    for j=1:length(names)
+        if isempty(names{j})
+            idxs = [idxs j];
+        end
+    end
+    simdata = sur(simdata{idxs});
+    BETA(i, :) = M_.params';
+    oo_ = rmfield(oo_, 'sur');
+end
+
+if NSIMS > 1
+    if max(abs(mean(BETA)' - calibrated_values)) > 1e-2
+        error(['sum(abs(mean(BETA)'' - calibrated_values)) ' num2str(sum(abs(mean(BETA)' - calibrated_values)))]);
+    end
+else
+    good = [-0.826686196809409
+        -0.346753563700393
+        0.063013991583949
+        0.074802596658698
+        -0.017440119721953
+        -0.127090614348862
+        0.025293280404460
+        0.524290302468866
+        -0.117611206771440
+        -0.027776224547132
+        -0.156590828735908
+        0.054039707976331
+        0.276257666502046
+        1.000417289621684
+        0.999336865129450
+        -0.803258152338916
+        -0.309594948488168
+        0.051602756230521
+        0.039275481081030
+        0.024897596371662
+        -0.096310133845385
+        -0.022630284059365
+        0.461683465196454
+        -0.110278113383114
+        1.000000000000000];
+    if max(abs(BETA' - good)) > 1e-14
+        error(['sum of BETA'' - good was: ' num2str(sum(abs(BETA - good)))]);
+    end
+    return
+end
+
+for i=1:nparampool
+    figure
+    hold on
+    title(strrep(M_.param_names(i,:), '_', '\_'));
+    histogram(BETA(:,i),50);
+    line([calibrated_values(i) calibrated_values(i)], [0 NSIMS/10], 'LineWidth', 2, 'Color', 'r');
+    hold off
+end
diff --git a/tests/ecb/SUR/panel_var_diff_NB_simulation_zero_eq.mod b/tests/ecb/SUR/panel_var_diff_NB_simulation_zero_eq.mod
new file mode 100644
index 0000000000000000000000000000000000000000..24667c57019d96e3a1f727d7e1da0b677e45f1fe
--- /dev/null
+++ b/tests/ecb/SUR/panel_var_diff_NB_simulation_zero_eq.mod
@@ -0,0 +1,222 @@
+// --+ options: json=compute +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_g_yer_u2_stn_L1
+de_ehic_de_ehic_L1
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+
+[name = 'eq4']
+U2_ESTN        =  0                                                       ;
+
+[name = 'eq5']
+U2_EHIC        =  0                                                       ;
+
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+
+[name = 'eq8']
+DE_EHIC        = DE_EHIC(-1) + res_DE_EHIC                                ;
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+NSIMS = 1;
+
+options_.noprint = 1;
+calibrated_values = M_.params;
+verbatim;
+Sigma_e = M_.Sigma_e;
+end;
+options_.bnlms.set_dynare_seed_to_default = false;
+
+nparampool = length(M_.params);
+BETA = zeros(NSIMS, nparampool);
+for i=1:NSIMS
+    firstobs = rand(3, length(M_.endo_names));
+    M_.params = calibrated_values;
+    M_.Sigma_e = Sigma_e;
+    simdata = simul_backward_model(dseries(firstobs, dates('1995Q1'), M_.endo_names), 10000);
+    simdata = simdata(simdata.dates(5001:6000));
+    % fill zeroed-out variables with random data to ensure they are not being referenced
+    simdata.U2_EHIC = dseries(rand(1000, 1), simdata.firstdate, 'U2_EHIC');
+    simdata.U2_ESTN = dseries(rand(1000, 1), simdata.firstdate, 'U2_ESTN');
+    names = regexp(simdata.name, 'res\w*');
+    idxs = [];
+    for j=1:length(names)
+        if isempty(names{j})
+            idxs = [idxs j];
+        end
+    end
+    simdata = sur(simdata{idxs});
+    BETA(i, :) = M_.params';
+    oo_ = rmfield(oo_, 'sur');
+end
+
+if NSIMS > 1
+    if max(abs(mean(BETA)' - calibrated_values)) > 1e-2
+        error(['sum(abs(mean(BETA)'' - calibrated_values)) ' num2str(sum(abs(mean(BETA)' - calibrated_values)))]);
+    end
+else
+    good = [-0.806260229719792
+        -0.354371215026078
+        0.067618717060638
+        0.088053231576354
+        -0.057161898696690
+        -0.136999143481575
+        0.052047088887385
+        0.524022502978068
+        -0.110211572532150
+        -0.041415758049800
+        -0.162997606880957
+        0.091000830792721
+        0.281196660545012
+        1.000000000000000
+        1.000000000000000
+        -0.823354793011220
+        -0.337521089381118
+        0.025493177305917
+        0.059513905441361
+        0.016845886773011
+        -0.151537340795868
+        0.004832174649536
+        0.430883913061161
+        -0.071743697511067
+        1.000000000000000];
+    if max(abs(BETA' - good)) > 1e-14
+        error(['sum of BETA'' - good was: ' num2str(sum(abs(BETA - good)))]);
+    end
+    return
+end
+
+for i=1:nparampool
+    figure
+    hold on
+    title(strrep(M_.param_names(i,:), '_', '\_'));
+    histogram(BETA(:,i),50);
+    line([calibrated_values(i) calibrated_values(i)], [0 NSIMS/10], 'LineWidth', 2, 'Color', 'r');
+    hold off
+end
diff --git a/tests/ecb/SUR/sur_noniterative.mod b/tests/ecb/SUR/sur_noniterative.mod
new file mode 100644
index 0000000000000000000000000000000000000000..35ef510bd4b5f76220f7b0eb1920b54077f91126
--- /dev/null
+++ b/tests/ecb/SUR/sur_noniterative.mod
@@ -0,0 +1,223 @@
+// --+ options: json=compute +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_g_yer_u2_stn_L1
+de_ehic_de_ehic_L1
+
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        = DE_EHIC(-1) + res_DE_EHIC                                ;
+
+
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+NSIMS = 1;
+
+options_.noprint = 1;
+calibrated_values = M_.params;
+verbatim;
+Sigma_e = M_.Sigma_e;
+end;
+options_.bnlms.set_dynare_seed_to_default = false;
+
+nparampool = length(M_.params);
+BETA = zeros(NSIMS, nparampool);
+for i=1:NSIMS
+    firstobs = rand(3, length(M_.endo_names));
+    M_.params = calibrated_values;
+    M_.Sigma_e = Sigma_e;
+    simdata = simul_backward_model(dseries(firstobs, dates('1995Q1'), M_.endo_names), 10000);
+    simdata = simdata(simdata.dates(5001:6000));
+    names=regexp(simdata.name, 'res\w*');
+    idxs = [];
+    for j=1:length(names)
+        if isempty(names{j})
+            idxs = [idxs j];
+        end
+    end
+    simdata = sur(simdata{idxs}, {}, {}, 'mymodel', true);
+    BETA(i, :) = M_.params';
+    oo_ = rmfield(oo_, 'sur');
+end
+
+if NSIMS > 1
+    if max(abs(mean(BETA)' - calibrated_values)) > 1e-2
+        error(['sum(abs(mean(BETA)'' - calibrated_values)) ' num2str(sum(abs(mean(BETA)' - calibrated_values)))]);
+    end
+else
+    good = [-0.826686383251952
+        -0.346754226737713
+        0.063012625739192
+        0.074803008678581
+        -0.017406695286611
+        -0.127075466955954
+        0.025273119798253
+        0.524311285013928
+        -0.117653504652072
+        -0.027795769946178
+        -0.156599054434094
+        0.054048691636616
+        0.276250884768198
+        1.000417819589230
+        0.999336022919911
+        -0.803262845969268
+        -0.309598590696623
+        0.051598925732525
+        0.039275097813797
+        0.024902442384228
+        -0.096310332265968
+        -0.022625946626029
+        0.461672601960238
+        -0.110232456667380
+        1.000000000000000];
+    if max(abs(BETA' - good)) > 1e-14
+        error(['sum of BETA'' - good was: ' num2str(sum(abs(BETA - good)))]);
+    end
+    return
+end
+
+for i=1:nparampool
+    figure
+    hold on
+    title(strrep(M_.param_names(i,:), '_', '\_'));
+    histogram(BETA(:,i),50);
+    line([calibrated_values(i) calibrated_values(i)], [0 NSIMS/10], 'LineWidth', 2, 'Color', 'r');
+    hold off
+end
diff --git a/tests/ecb/SUR/sur_params_noniterative.mod b/tests/ecb/SUR/sur_params_noniterative.mod
new file mode 100644
index 0000000000000000000000000000000000000000..268ae3d30884da434688850ef5c8691f9506eee9
--- /dev/null
+++ b/tests/ecb/SUR/sur_params_noniterative.mod
@@ -0,0 +1,222 @@
+// --+ options: json=compute +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_g_yer_u2_stn_L1
+de_ehic_de_ehic_L1
+
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        = DE_EHIC(-1) + res_DE_EHIC                                ;
+
+
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+NSIMS = 1;
+
+options_.noprint = 1;
+calibrated_values = M_.params;
+verbatim;
+Sigma_e = M_.Sigma_e;
+end;
+options_.bnlms.set_dynare_seed_to_default = false;
+
+nparampool = length(M_.params);
+BETA = zeros(NSIMS, nparampool);
+for i=1:NSIMS
+    firstobs = rand(3, length(M_.endo_names));
+    M_.params = calibrated_values;
+    M_.Sigma_e = Sigma_e;
+    simdata = simul_backward_model(dseries(firstobs, dates('1995Q1'), M_.endo_names), 10000);
+    simdata = simdata(simdata.dates(5001:6000));
+    names=regexp(simdata.name, 'res\w*');
+    idxs = [];
+    for j=1:length(names)
+        if isempty(names{j})
+            idxs = [idxs j];
+        end
+    end
+    simdata = sur(simdata{idxs}, {'u2_q_yed_u2_g_yer_L1', 'u2_estn_u2_estn_L1', 'u2_ehic_u2_ehic_L1', 'de_q_yed_de_g_yer_L1', 'u2_g_yer_u2_g_yer_L1', 'u2_stn_u2_q_yed_L1', 'u2_q_yed_ecm_u2_q_yed_L1', 'de_g_yer_u2_stn_L1'}, {}, 'mymodel', true);
+    BETA(i, :) = M_.params';
+    oo_ = rmfield(oo_, 'sur');
+end
+if NSIMS > 1
+    if max(abs(mean(BETA)' - calibrated_values)) > 1e-2
+        error(['sum(abs(mean(BETA)'' - calibrated_values)) ' num2str(sum(abs(mean(BETA)' - calibrated_values)))]);
+    end
+else
+    good = [-0.811559435201128
+        -0.323715338568976
+        0.073666282610569
+        0.058397703958446
+        0.018989604697742
+        -0.109597659887432
+        0.003766796763203
+        0.510389966839712
+        -0.072235928612349
+        -0.043850066260836
+        -0.153283917138772
+        0.058739144948151
+        0.292121949736756
+        1.000413662363949
+        0.999337514406012
+        -0.822375165893149
+        -0.323715338568977
+        0.046096335070402
+        0.058397703958446
+        0.018989604697742
+        -0.109597659887433
+        0.003766796763203
+        0.480506381923643
+        -0.111002148299648
+        1.000000000000000];
+    if max(abs(BETA' - good)) > 1e-14
+        error(['sum of BETA'' - good was: ' num2str(sum(abs(BETA - good)))]);
+    end
+    return
+end
+
+for i=1:nparampool
+    figure
+    hold on
+    title(strrep(M_.param_names(i,:), '_', '\_'));
+    histogram(BETA(:,i),50);
+    line([calibrated_values(i) calibrated_values(i)], [0 NSIMS/10], 'LineWidth', 2, 'Color', 'r');
+    hold off
+end
diff --git a/tests/ecb/SURGibbs/fishdata.csv b/tests/ecb/SURGibbs/fishdata.csv
new file mode 100644
index 0000000000000000000000000000000000000000..5d525ab7a5b011a0cf0d75abd234261d6cea78c7
--- /dev/null
+++ b/tests/ecb/SURGibbs/fishdata.csv
@@ -0,0 +1,112 @@
+day1,day2,day3,day4,date,stormy,mixed,price,qty,rainy,cold,windspd,windspd2,pricelevel,totr,tots
+1,0,0,0,911202,1,0,-0.4307829,8.994421,1,0,2.995732,8.974412,0.65,7232,8058
+0,1,0,0,911203,1,0,0,7.707063,0,0,2.995732,8.974412,1,2110,2224
+0,0,1,0,911204,0,1,0.0723207,8.350194,1,1,2.813411,7.91528,1.075,5247,4231
+0,0,0,1,911205,1,0,0.247139,8.656955,0,1,3.036554,9.220662,1.280357,1290,5750
+0,0,0,0,911206,1,0,0.6643268,7.844241,0,1,3.036554,9.220662,1.943182,1717,2551
+1,0,0,0,911209,0,0,-0.2065143,9.301277,0,0,2.762117,7.629292,0.8134146,11643,10977
+0,1,0,0,911210,0,1,-0.1158318,8.920656,0,0,2.762117,7.629292,0.890625,9640,7485
+0,0,1,0,911211,0,0,-0.2598674,9.105979,1,0,2.762117,7.629292,0.7711539,9347,9009
+0,0,0,1,911212,0,1,-0.1171254,8.307706,0,0,2.762117,7.629292,0.8894737,3890,4055
+0,0,0,0,911213,0,0,-0.3420761,9.20954,0,0,2.590267,6.709484,0.7102941,16318,9992
+1,0,0,0,911216,1,0,-0.1255632,8.552561,0,1,3.149883,9.921763,0.882,8725,5180
+0,1,0,0,911217,1,0,0.027399,8.523175,0,1,3.218876,10.36116,1.027778,2780,5030
+0,0,1,0,911218,1,0,-0.0712275,8.865453,0,1,3.184974,10.14406,0.93125,9078,6833
+0,0,0,1,911219,1,0,0.1230601,9.186355,0,1,3.113515,9.693978,1.130952,5066,9763
+0,0,0,0,911220,1,0,0.2130932,8.699348,0,1,3.149883,9.921763,1.2375,4796,5999
+1,0,0,0,911223,0,1,-0.3172045,9.408863,0,1,2.953173,8.721229,0.7281818,13647,12196
+0,1,0,0,911224,0,1,-0.1088388,8.150179,0,1,3.036554,9.220662,0.896875,1255,3464
+0,0,0,1,911226,0,1,0.2231435,6.703188,0,1,2.953173,8.721229,1.25,1115,815
+0,0,0,0,911227,0,0,0.2464593,8.798907,0,1,2.862201,8.192194,1.279487,6887,6627
+1,0,0,0,911230,0,0,-0.075431,9.565214,1,1,2.70805,7.333536,0.9273437,15894,14260
+0,1,0,0,911231,0,0,0.2055992,8.297792,1,1,2.862201,8.192194,1.228261,5850,4015
+0,0,0,1,920102,0,0,0.2188098,8.320935,0,0,2.813411,7.91528,1.244595,409,4109
+0,0,0,0,920103,0,0,0.307025,8.884887,0,0,2.456736,6.035551,1.359375,7222,7222
+1,0,0,0,920106,1,0,0.399592,9.336444,0,0,3.314186,10.98383,1.491216,13036,11224
+0,1,0,0,920107,1,0,0.4969802,8.122668,0,1,3.344039,11.1826,1.64375,1760,3370
+0,0,1,0,920108,1,0,0.3968258,8.15191,0,1,3.036554,9.220662,1.487097,4824,3470
+0,0,0,1,920109,0,1,0.2830518,9.51834,0,1,2.813411,7.91528,1.327174,16489,13607
+0,0,0,0,920110,0,1,0.2263384,8.567886,1,0,2.650892,7.027227,1.254,4842,5260
+1,0,0,0,920113,0,1,-0.0723207,9.386811,0,0,2.908721,8.460658,0.9302325,12732,11930
+0,1,0,0,920114,0,1,-0.1545295,8.628735,0,0,2.813411,7.91528,0.8568182,7070,5590
+0,0,1,0,920115,1,0,0.2363888,7.727535,1,1,2.995732,8.974412,1.266667,2873,2270
+0,0,0,1,920116,1,0,0.1718503,8.453188,0,1,3.113515,9.693978,1.1875,1915,4690
+0,0,0,0,920117,1,0,0.1541506,7.156956,1,1,3.218876,10.36116,1.166667,240,1283
+1,0,0,0,920120,1,0,0.0350913,6.363028,0,1,3.075775,9.460391,1.035714,300,580
+0,1,0,0,920121,0,1,0.218131,7.313221,1,1,3.075775,9.460391,1.24375,1960,1550
+0,0,1,0,920122,0,0,-0.0624355,8.39163,0,1,2.908721,8.460658,0.9394737,5408,4410
+0,0,0,1,920123,0,0,-0.4418328,9.188503,0,0,2.70805,7.333536,0.6428571,10130,9909
+0,0,0,0,920124,0,0,-0.7699343,9.318297,1,0,2.862201,8.192194,0.4630435,12943,11140
+1,0,0,0,920127,1,0,-0.7391911,8.363809,1,1,3.113515,9.693978,0.4775,2766,4289
+0,1,0,0,920128,0,1,-0.7230001,8.621193,0,1,2.862201,8.192194,0.4852941,4050,5548
+0,0,1,0,920129,0,0,-0.5184302,8.144679,0,1,2.813411,7.91528,0.5954546,6208,3445
+0,0,0,1,920130,0,0,-0.5533853,8.710784,0,1,2.650892,7.027227,0.575,7539,6151
+0,0,0,0,920131,0,0,-0.5590724,8.417373,0,0,2.650892,7.027227,0.5717391,6250,4525
+1,0,0,0,920203,1,0,-0.4238143,9.017968,0,1,3.251666,10.57333,0.6545454,8620,8250
+0,1,0,0,920204,1,0,-0.7731899,7.528332,0,1,3.283414,10.78081,0.4615385,300,1860
+0,0,1,0,920205,1,0,-0.2040953,7.154615,0,1,3.075775,9.460391,0.8153846,360,1280
+0,0,0,1,920206,1,0,0.3841877,8.487764,0,1,3.075775,9.460391,1.468421,5680,4855
+0,0,0,0,920207,0,1,0.3479887,8.979543,0,1,2.953173,8.721229,1.416216,7484,8089
+1,0,0,0,920210,1,0,0.3229889,8.744328,0,1,3.036554,9.220662,1.38125,6960,6275
+0,1,0,0,920211,1,0,0.4345259,7.893572,0,1,2.953173,8.721229,1.544231,2460,2680
+0,0,1,0,920212,1,0,0.2000211,8.5923,0,1,2.908721,8.460658,1.221429,8396,5390
+0,0,0,1,920213,0,1,-0.0071685,9.035987,0,1,2.862201,8.192194,0.9928572,14440,8400
+0,0,0,0,920214,0,1,-0.4744579,9.525735,0,1,2.862201,8.192194,0.6222222,7095,13708
+0,1,0,0,920218,0,0,-0.7711087,9.773094,0,1,2.862201,8.192194,0.4625,19698,17555
+0,0,1,0,920219,0,1,-1.094774,8.158802,0,0,2.813411,7.91528,0.3346154,10,3474
+0,0,0,1,920220,0,0,-0.8602012,8.677609,0,0,2.70805,7.333536,0.4230769,6470,5870
+0,0,0,0,920221,0,1,-0.597837,9.034796,0,0,2.762117,7.629292,0.55,6695,8390
+1,0,0,0,920224,0,0,-0.567984,8.375629,0,1,2.525729,6.379305,0.5666667,5222,4340
+0,1,0,0,920225,0,0,-0.7711087,7.649693,0,1,2.590267,6.709484,0.4625,2885,2100
+0,0,1,0,920226,0,1,-0.2724146,7.853605,0,1,2.862201,8.192194,0.7615384,2025,2575
+0,0,0,1,920227,1,0,0.1849223,7.955074,1,1,2.953173,8.721229,1.203125,1179,2850
+0,0,0,0,920228,1,0,0.20676,8.73069,0,0,2.908721,8.460658,1.229687,7420,6190
+1,0,0,0,920302,0,1,0.074108,8.633197,0,0,2.908721,8.460658,1.076923,5855,5635
+0,1,0,0,920303,1,0,-0.0071685,8.796339,0,1,2.908721,8.460658,0.9928572,7327,6730
+0,0,1,0,920304,0,1,-0.2548923,8.994048,0,0,2.762117,7.629292,0.775,7850,8055
+0,0,0,1,920305,0,1,-0.2364898,9.22375,0,0,2.650892,7.027227,0.789394,8610,10135
+0,0,0,0,920306,0,0,-0.4848501,8.568457,0,0,2.590267,6.709484,0.6157895,5213,5263
+1,0,0,0,920309,0,1,-0.8119307,9.981374,0,0,2.862201,8.192194,0.444,26530,21620
+0,1,0,0,920310,0,1,-0.4780358,9.172119,0,0,2.813411,7.91528,0.62,4520,9685
+0,0,1,0,920311,0,1,-0.2301122,8.116715,0,1,2.762117,7.629292,0.7944444,3375,3350
+0,0,0,1,920312,1,0,-0.2887938,9.241354,1,1,3.075775,9.460391,0.7491667,10600,11015
+0,0,0,0,920313,1,0,-0.3409266,8.016318,0,1,3.283414,10.78081,0.7111111,21070,3030
+1,0,0,0,920316,0,0,-0.4812668,9.646011,0,1,2.862201,8.192194,0.618,250,15520
+0,1,0,0,920317,0,0,-0.5817336,9.168476,0,1,2.813411,7.91528,0.5589285,7610,9590
+0,0,1,0,920318,0,1,-0.0370413,7.44132,0,1,2.908721,8.460658,0.9636363,3065,1705
+0,0,0,1,920319,0,0,0.0746435,8.61432,0,1,2.813411,7.91528,1.0775,3830,5510
+0,0,0,0,920320,1,0,-0.5268259,8.902047,1,1,3.075775,9.460391,0.5904762,8342,7347
+1,0,0,0,920323,0,0,-0.1123292,7.857481,0,1,2.590267,6.709484,0.89375,2305,2585
+0,1,0,0,920324,0,1,-0.2376716,8.228177,0,1,2.762117,7.629292,0.7884616,4410,3745
+0,0,1,0,920325,0,1,-0.4243931,7.986165,0,1,2.762117,7.629292,0.6541666,3000,2940
+0,0,0,1,920326,0,1,-0.4828126,9.395989,0,0,2.862201,8.192194,0.6170455,11783,12140
+0,0,0,0,920327,0,1,-0.1923718,7.711997,0,0,2.862201,8.192194,0.825,2535,2295
+1,0,0,0,920330,1,0,0.1823216,7.705263,0,0,3.401197,11.56814,1.2,5130,2220
+0,1,0,0,920331,1,0,0.2876821,7.013916,0,0,3.184974,10.14406,1.333333,514,1112
+0,0,1,0,920401,0,1,-0.1873341,8.492901,1,0,2.953173,8.721229,0.8291667,3920,4940
+0,0,0,1,920402,0,0,-0.4404448,9.333443,0,0,2.590267,6.709484,0.64375,10240,11310
+0,0,0,0,920403,0,0,-0.567984,9.578795,1,1,2.862201,8.192194,0.5666667,15042,14480
+1,0,0,0,920406,0,0,-0.3873608,8.975504,0,0,2.813411,7.91528,0.6788461,6852,7727
+0,1,0,0,920407,0,0,-0.5108256,7.28961,0,0,2.70805,7.333536,0.6,305,1465
+0,0,1,0,920408,0,0,-0.6149098,9.415728,0,0,2.70805,7.333536,0.5406896,14148,12280
+0,0,0,1,920409,0,0,-0.3876929,8.740336,0,0,2.650892,7.027227,0.6786207,5160,6250
+0,0,0,0,920410,0,0,-0.3716677,8.584852,0,0,2.650892,7.027227,0.6895834,4340,5350
+1,0,0,0,920413,0,0,-0.3101549,8.657825,0,1,2.862201,8.192194,0.7333333,7049,5535
+0,1,0,0,920414,0,0,-0.3502024,7.383989,0,0,2.995732,8.974412,0.7045454,200,2260
+0,0,1,0,920415,0,0,-0.2231435,6.194406,0,0,2.762117,7.629292,0.8,360,490
+0,0,0,1,920416,0,0,-0.3119048,9.187583,0,0,2.525729,6.379305,0.7320513,11875,9655
+0,0,0,0,920417,0,0,-0.2258646,8.779557,1,0,2.456736,6.035551,0.7978261,3900,6050
+0,1,0,0,920421,0,0,-0.2842691,9.261033,0,0,2.590267,6.709484,0.7525641,10700,10494
+0,0,1,0,920422,0,0,-0.0971638,8.294049,0,0,2.525729,6.379305,0.9074074,3940,4118
+0,0,0,1,920423,0,0,-0.1419181,8.737132,1,0,2.650892,7.027227,0.8676924,6570,5910
+0,0,0,0,920424,0,0,-0.5364382,9.651816,0,0,2.650892,7.027227,0.5848276,15940,15455
+1,0,0,0,920427,0,0,-0.4596867,8.552561,0,0,2.650892,7.027227,0.6314815,8170,5060
+0,1,0,0,920428,0,0,-0.4866114,8.163371,0,0,2.590267,6.709484,0.6147059,1676,3300
+0,0,1,0,920429,0,0,-0.7603559,8.663024,0,0,2.525729,6.379305,0.4675,6963,5785
+0,0,0,1,920430,0,0,-0.8931236,9.099409,0,0,2.525729,6.379305,0.409375,7694,9050
+0,0,0,0,920501,0,0,-1.107745,9.014325,0,0,2.525729,6.379305,0.330303,11370,8520
+1,0,0,0,920504,0,0,-0.7985078,8.610683,0,0,2.862201,8.192194,0.45,1610,6260
+0,1,0,0,920505,0,1,-0.0870114,7.162397,0,0,2.908721,8.460658,0.9166666,1320,1290
+0,0,1,0,920506,0,1,0.1849223,7.36201,0,0,2.862201,8.192194,1.203125,2305,1450
+0,0,0,1,920507,0,1,0.2231435,8.764053,0,0,2.813411,7.91528,1.25,6080,4780
+0,0,0,0,920508,0,1,0.5611184,8.328451,0,0,2.862201,8.192194,1.752632,4020,3420
diff --git a/tests/ecb/SURGibbs/fulton_fish.mod b/tests/ecb/SURGibbs/fulton_fish.mod
new file mode 100644
index 0000000000000000000000000000000000000000..23e8c8f41150e7d37afe1a5af5fefac830c2b820
--- /dev/null
+++ b/tests/ecb/SURGibbs/fulton_fish.mod
@@ -0,0 +1,43 @@
+// --+ options: json=compute +--
+% Example from Section 6.1 of
+% Ando, Tomohiro and Zellner, Arnold. 2010. Hierarchical Bayesian Analysis of the
+% Seemingly Unrelated Regression and Simultaneous Equations Models Using a
+% Combination of Direct Monte Carlo and Importance Sampling Techniques.
+% Bayesian Analysis Volume 5, Number 1, pp. 65-96.
+
+var qty, price;
+varexo res_u, res_v, stormy, mixed;
+parameters bq0, bp0, bq1, bp1, bp2;
+
+bp0 =  8.5527;
+bp1 = -0.5302;
+bp2 = -0.3974;
+
+bq0 =  6.7523;
+bq1 = -0.7969;
+
+model(linear);
+    qty = bq0 + bq1*price + res_u;
+    price = bp0 + bp1*stormy + bp2*mixed + res_v;
+end;
+
+% Estimate all parameters
+%estparams = M_.param_names;
+%estparamsval = M_.params;
+
+% Estimate demand parameters
+estparams = {'bq1' 'bq0'};
+estparamsval = [bq1 bq0];
+
+A = 0.0005.*eye(length(estparams));
+simdata = surgibbs(dseries('fishdata.csv'), estparams, estparamsval, A, 20000, 5000, 7);
+
+good = [6.791587808530124
+   8.552700000000000
+  -0.478275288902356
+  -0.530200000000000
+  -0.397400000000000];
+
+if sum(abs(M_.params-good)) > 2e-14
+    error(['sum of M_.params - good was: ' num2str(sum(abs(M_.params-good)))]);
+end
diff --git a/tests/ecb/aggregate/1/endogenous.inc b/tests/ecb/aggregate/1/endogenous.inc
new file mode 100644
index 0000000000000000000000000000000000000000..3eee499b9fca5b2036f48f8886370b61723b8e31
--- /dev/null
+++ b/tests/ecb/aggregate/1/endogenous.inc
@@ -0,0 +1,5 @@
+var
+    x1 (kind='toto',regress='true')
+    y1
+    z1 (kind='toto')
+    nu1;
\ No newline at end of file
diff --git a/tests/ecb/aggregate/1/exogenous.inc b/tests/ecb/aggregate/1/exogenous.inc
new file mode 100644
index 0000000000000000000000000000000000000000..eb9af7bb49342ab95e8b9d25402ec27e3326c808
--- /dev/null
+++ b/tests/ecb/aggregate/1/exogenous.inc
@@ -0,0 +1,4 @@
+varexo
+    ex1 (dist='Gamma')
+    ey1 (dist='Gaussian')
+    ez1 (dist='Gamma');
\ No newline at end of file
diff --git a/tests/ecb/aggregate/1/model.inc b/tests/ecb/aggregate/1/model.inc
new file mode 100644
index 0000000000000000000000000000000000000000..209bb208e562129edf3f39df4995c54d4fe4ed5d
--- /dev/null
+++ b/tests/ecb/aggregate/1/model.inc
@@ -0,0 +1,7 @@
+[name='eq:x1']
+x1 = a1*x1(-1)+b1*nu1+c1*y1(-2)+ex1;
+
+y1 = d1*x1(-1)+e1*nu1(-1)+f1*z1(-1)+ey1;
+
+[name='eq:z1']
+z1 = g1*z1(-1)+ez1;
\ No newline at end of file
diff --git a/tests/ecb/aggregate/1/parameter-values.inc b/tests/ecb/aggregate/1/parameter-values.inc
new file mode 100644
index 0000000000000000000000000000000000000000..a9cd8ce5ac45f27ef51ce14473ef26142be3c144
--- /dev/null
+++ b/tests/ecb/aggregate/1/parameter-values.inc
@@ -0,0 +1,7 @@
+a1 = .1;
+b1 = .2;
+c1 = .3;
+d1 = .4;
+e1 = .5;
+f1 = .6;
+g1 = .7;
\ No newline at end of file
diff --git a/tests/ecb/aggregate/1/parameters.inc b/tests/ecb/aggregate/1/parameters.inc
new file mode 100644
index 0000000000000000000000000000000000000000..8fa3ab227069d680c174c7bce64978fbd77ccef8
--- /dev/null
+++ b/tests/ecb/aggregate/1/parameters.inc
@@ -0,0 +1 @@
+parameters a1 b1 c1 d1 e1 f1 g1;
\ No newline at end of file
diff --git a/tests/ecb/aggregate/2/endogenous.inc b/tests/ecb/aggregate/2/endogenous.inc
new file mode 100644
index 0000000000000000000000000000000000000000..1769a1421bd5a287571b4430d0ed09f110c947b0
--- /dev/null
+++ b/tests/ecb/aggregate/2/endogenous.inc
@@ -0,0 +1,5 @@
+var
+    x2
+    y2 (kind='toto') 
+    z2
+    nu2;
\ No newline at end of file
diff --git a/tests/ecb/aggregate/2/exogenous.inc b/tests/ecb/aggregate/2/exogenous.inc
new file mode 100644
index 0000000000000000000000000000000000000000..bdef1f196f1208180550e2342adf00de714e97e5
--- /dev/null
+++ b/tests/ecb/aggregate/2/exogenous.inc
@@ -0,0 +1,4 @@
+varexo
+    ex2 (dist='Gamma')
+    ey2 (dist='Gaussian')
+    ez2 (dist='Gamma');
\ No newline at end of file
diff --git a/tests/ecb/aggregate/2/model.inc b/tests/ecb/aggregate/2/model.inc
new file mode 100644
index 0000000000000000000000000000000000000000..38f8c620d4cd1ba2fa96312781c19db2e4b65fd1
--- /dev/null
+++ b/tests/ecb/aggregate/2/model.inc
@@ -0,0 +1,7 @@
+x2 = a2*x2(-1)+b2*nu2+c2*y2(-2)+ex2;
+
+[name='eq:y2']
+y2 = d2*x2(-1)+e2*nu2(-1)+f2*z2(-1)+ey2;
+
+[name='eq:z2']
+diff(z2) = g2*z2(-1)+ez2;
\ No newline at end of file
diff --git a/tests/ecb/aggregate/2/parameter-values.inc b/tests/ecb/aggregate/2/parameter-values.inc
new file mode 100644
index 0000000000000000000000000000000000000000..7eab0b0d9e98566aba39437cadce5761dd649b43
--- /dev/null
+++ b/tests/ecb/aggregate/2/parameter-values.inc
@@ -0,0 +1,7 @@
+a2 = -.1;
+b2 = -.2;
+c2 = -.3;
+d2 = -.4;
+e2 = -.5;
+f2 = -.6;
+g2 = -.7;
\ No newline at end of file
diff --git a/tests/ecb/aggregate/2/parameters.inc b/tests/ecb/aggregate/2/parameters.inc
new file mode 100644
index 0000000000000000000000000000000000000000..7bec3b9e963a4c84650d15fe2fde659ee2de06c9
--- /dev/null
+++ b/tests/ecb/aggregate/2/parameters.inc
@@ -0,0 +1 @@
+parameters a2 b2 c2 d2 e2 f2 g2;
\ No newline at end of file
diff --git a/tests/ecb/aggregate/3/endogenous.inc b/tests/ecb/aggregate/3/endogenous.inc
new file mode 100644
index 0000000000000000000000000000000000000000..6bc2845be413e20c601769f5ac0f2bb6388efa77
--- /dev/null
+++ b/tests/ecb/aggregate/3/endogenous.inc
@@ -0,0 +1,5 @@
+var
+    x3
+    y3
+    z3
+    nu3;
\ No newline at end of file
diff --git a/tests/ecb/aggregate/3/exogenous.inc b/tests/ecb/aggregate/3/exogenous.inc
new file mode 100644
index 0000000000000000000000000000000000000000..78b0c6b3c97f6f38dfd1b5aab0559732ae98301e
--- /dev/null
+++ b/tests/ecb/aggregate/3/exogenous.inc
@@ -0,0 +1,4 @@
+varexo
+    ex3
+    ey3
+    ez3;
\ No newline at end of file
diff --git a/tests/ecb/aggregate/3/model.inc b/tests/ecb/aggregate/3/model.inc
new file mode 100644
index 0000000000000000000000000000000000000000..aa95e840bf3f6eb5572b9264229c42240f1df156
--- /dev/null
+++ b/tests/ecb/aggregate/3/model.inc
@@ -0,0 +1,8 @@
+[name='eq:x3']
+x3 = a2*x3(-1)+b3*nu3+c3*y3(-2)+ex3;
+
+[name='eq:y3']
+diff(-diff(y3)) = d3*diff(x3(-1))+e3*nu3(-1)+f3*z3(-1)+ey3;
+
+[name='eq:z3']
+diff(log(-z3)) = g3*log(-z3(-1))+ez3;
\ No newline at end of file
diff --git a/tests/ecb/aggregate/3/parameter-values.inc b/tests/ecb/aggregate/3/parameter-values.inc
new file mode 100644
index 0000000000000000000000000000000000000000..5650b370df52e1b33fd325bb08051be5c3237fa8
--- /dev/null
+++ b/tests/ecb/aggregate/3/parameter-values.inc
@@ -0,0 +1,7 @@
+a3 = -.1;
+b3 = -.2;
+c3 = -.3;
+d3 = -.4;
+e3 = -.5;
+f3 = -.6;
+g3 = -.7;
\ No newline at end of file
diff --git a/tests/ecb/aggregate/3/parameters.inc b/tests/ecb/aggregate/3/parameters.inc
new file mode 100644
index 0000000000000000000000000000000000000000..f64aed1e0825a37408a1e6ecdc9257e809b5cffd
--- /dev/null
+++ b/tests/ecb/aggregate/3/parameters.inc
@@ -0,0 +1 @@
+parameters a3 b3 c3 d3 e3 f3 g3;
\ No newline at end of file
diff --git a/tests/ecb/backward-models/solow_irf.mod b/tests/ecb/backward-models/irf/solow_1.mod
similarity index 81%
rename from tests/ecb/backward-models/solow_irf.mod
rename to tests/ecb/backward-models/irf/solow_1.mod
index a4b36478defa4924228249b3cbccca2ca5e5d889..6c0f41fe3ae849e01d645ef340381e1eb8563783 100644
--- a/tests/ecb/backward-models/solow_irf.mod
+++ b/tests/ecb/backward-models/irf/solow_1.mod
@@ -49,7 +49,17 @@ end;
 ds = dseries(repmat([1, .5, 1, .5, 0, 1], 10, 1), 1990Q1, M_.endo_names, M_.endo_names_tex);
 
 // Alternatively we could build this object with a stochastic simulation of the model.
-//oo_ = simul_backward_model(rand(6,1), 10, options_, M_, oo_);
+/*
+ds = simul_backward_model(dseries([1, .5, 1, .5, 0, 1], 1990Q1, cellstr(M_.endo_names)), 10);
+names=regexp(ds.name, 'e_\w*');
+idxs = [];
+for j=1:length(names)
+    if isempty(names{j})
+        idxs = [idxs j];
+    end
+end
+ds = ds{idxs};
+*/
 
 // Set the initial condition for the IRFs using observation 1991Q1 in ds.
 set_historical_values ds 1991Q1;
@@ -61,7 +71,7 @@ listofshocks = {'e_x', 'e_n'};
 listofvariables = {'Efficiency', 'Population', 'Output'};
 
 // Compute the IRFs
-irfs = backward_model_irf(1991Q1, listofshocks, listofvariables, 50);  // 10 is the number of periods (default value is 40).
+irfs = backward_model_irf(ds, dseries(), listofshocks, listofvariables, 50);  // 10 is the number of periods (default value is 40).
 
 // Plot an IRF (shock on technology)
 figure(1)
@@ -76,6 +86,7 @@ title('IRF (shock on the growth rate of efficiency)')
 ** the period of the initial condition).
 */
 
+/*
 histval;
   Efficiency(0) = 1;
   EfficiencyGrowth(0) = .5;
@@ -83,7 +94,7 @@ histval;
   PopulationGrowth(0) = .5;
   PhysicalCapitalStock(0) = 1;
 end;
-
+*/
 // Define the shocks for which we want to compute the IRFs
 listofshocks = {'e_x', 'e_n'};
 
@@ -91,16 +102,10 @@ listofshocks = {'e_x', 'e_n'};
 listofvariables = {'Efficiency', 'Population', 'Output'};
 
 // Compute the IRFs
-irfs = backward_model_irf(1991Q1, listofshocks, listofvariables, 50);  // 10 is the number of periods (default value is 40).
+irfs = backward_model_irf([], dseries(), listofshocks, listofvariables, 50);  // 10 is the number of periods (default value is 40).
 
 // Plot an IRF (shock on technology)
 figure(2)
 plot(irfs.e_x.Output)
 legend('Output')
-title('IRF (shock on the growth rate of efficiency)')
-
-/* REMARK
-** ------
-**
-** This model is nonlinear and non stationary. For different initial conditions the IRFs may look quite different. 
-*/
\ No newline at end of file
+title('IRF (shock on the growth rate of efficiency)')
\ No newline at end of file
diff --git a/tests/ecb/backward-models/irf/solow_2.mod b/tests/ecb/backward-models/irf/solow_2.mod
new file mode 100644
index 0000000000000000000000000000000000000000..f4b22043cb474fdbc7846d496a16dfea9cf884d7
--- /dev/null
+++ b/tests/ecb/backward-models/irf/solow_2.mod
@@ -0,0 +1,92 @@
+close all
+
+var Efficiency $A$
+    EfficiencyGrowth $X$
+    Population $L$
+    PopulationGrowth $N$
+    Output $Y$
+    PhysicalCapitalStock $K$ ;
+
+varexo e_x $\varepsilon_x$
+       e_n $\varepsilon_n$;
+
+parameters alpha $\alpha$
+	   delta $\delta$
+	   s $s$
+           rho_x $\rho_x$
+           rho_n $\rho_n$
+           EfficiencyGrowth_ss $X^{\star}$
+           PopulationGrowth_ss $N^{\star}$ ;
+
+alpha = .33;
+delta = .02;
+s     = .20;
+rho_x = .90;
+rho_n = .95;
+EfficiencyGrowth_ss = 1.0;
+PopulationGrowth_ss = 1.0;
+
+model;
+    Efficiency = EfficiencyGrowth*Efficiency(-1);
+    EfficiencyGrowth/EfficiencyGrowth_ss = (EfficiencyGrowth(-1)/EfficiencyGrowth_ss)^(rho_x)*exp(e_x);
+    Population = PopulationGrowth*Population(-1);
+    PopulationGrowth/PopulationGrowth_ss = (PopulationGrowth(-1)/PopulationGrowth_ss)^(rho_n)*exp(e_n);
+    Output = PhysicalCapitalStock(-1)^alpha*(Efficiency*Population)^(1-alpha);
+    PhysicalCapitalStock = (1-delta)*PhysicalCapitalStock(-1) + s*Output;
+end;
+
+
+shocks;
+    var e_x = 0.005;
+    var e_n = 0.001;
+end;
+
+histval;
+  Efficiency(0) = 1;
+  EfficiencyGrowth(0) = .5;
+  Population(0) = 1;
+  PopulationGrowth(0) = .5;
+  PhysicalCapitalStock(0) = 1;
+end;
+
+
+/*
+** First approach: Use the covariance matrix to define the impulses.
+*/
+
+// Define the shocks for which we want to compute the IRFs
+listofshocks = {'e_x', 'e_n'};
+
+// Define the variables for which we want to compute the IRFs
+listofvariables = {'Efficiency', 'Population', 'Output'};
+
+// Compute the IRFs
+irfs1 = backward_model_irf([], dseries(), listofshocks, listofvariables, 50);
+
+/*
+** Second approach: Explicitely comunnicate the paths for the exogneous variables.
+*/
+
+x0 = zeros(50,2);
+x0_1 = x0;
+x0_2 = x0;
+x0_1(1,1) = sqrt(M_.Sigma_e(1,1));
+x0_2(1,2) = sqrt(M_.Sigma_e(2,2));
+
+simshocks = {dseries(x0_1, 2, M_.exo_names), dseries(x0_2, 2, M_.exo_names) };
+
+// Compute the IRFs
+irfs2 = backward_model_irf([], dseries(), simshocks, listofvariables, 50);
+
+/*
+** Check that the two approaches do provide the same results.
+*/
+
+verbatim;
+  if max(abs(irfs1.e_x.Efficiency.data-irfs2.experiment_1.Efficiency.data))>1e-12
+    error('There is something wrong in the IRFs.')
+  end
+  if max(abs(irfs1.e_x.Output.data-irfs2.experiment_1.Output.data))>1e-12
+    error('There is something wrong in the IRFs.')
+  end
+end;
\ No newline at end of file
diff --git a/tests/ecb/backward-models/solow_forecast.mod b/tests/ecb/backward-models/solow_forecast.mod
index b76d5f2f2194ebfe20172a0b16e83ed25a82c5b3..6832141423c0d9839e6a4588c630f00358a13e08 100644
--- a/tests/ecb/backward-models/solow_forecast.mod
+++ b/tests/ecb/backward-models/solow_forecast.mod
@@ -51,9 +51,9 @@ histval;
     PhysicalCapitalStock(0) = 1;
 end;
 
-oo__ = simul_backward_nonlinear_model([], 10, options_, M_, oo_);
+simulation__ = simul_backward_nonlinear_model([], 10, options_, M_, oo_);
 
-initialcondition = dseries(transpose(oo__.endo_simul(:,10)), 2017Q1, M_.endo_names);
+initialcondition = dseries(simulation__.data(10,1:M_.endo_nbr), 2017Q1, M_.endo_names);
 
 
 /* REMARKS
diff --git a/tests/ecb/cherrypick/test1.mod b/tests/ecb/cherrypick/test1.mod
new file mode 100644
index 0000000000000000000000000000000000000000..be64d23f256628a08917e972acde3e795527abe0
--- /dev/null
+++ b/tests/ecb/cherrypick/test1.mod
@@ -0,0 +1,131 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x u v s azertyuiopiop z1 z2 z3;
+
+varexo ex1
+       ex2
+       ex1bar (used='estimationonly')
+       ex2bar (used='estimationonly')
+       ez
+       ey
+       ex
+       eu
+       ev
+       es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s cx cy beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+cx = 1.0;
+cy = 1.0;
+
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:u']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:azertyuiopiop', rename='azertyuiopiop->qsdfghjklm']
+azertyuiopiop = x + y;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( cy*y + cx*x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+[name='z1']
+z1 = z+y-x+u;
+
+[name='z2']
+z2 = z-y+x-u;
+
+[name='z3']
+z3 = u-diff(v);
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.1;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Select a subset of the equations and print the equations, the list of parameters, endogenous
+// variables and exogenous variables in .inc files under ./simulation-files folder. Note that
+// innovations ex1bar and ex2bar will not appear in the equations.
+verbatim;
+  cherrypick('test1', 'simulation-files1', {'z1', 'z2', 'z3'}, true);
+  cherrypick('test1', 'simulation-files2', {'zpac', 'eq:x1', 'eq:x', 'eq:y'}, true);
+  aggregate('toto.mod', {}, '', 'simulation-files1', 'simulation-files2');
+end;
diff --git a/tests/ecb/cherrypick/test2.mod b/tests/ecb/cherrypick/test2.mod
new file mode 100644
index 0000000000000000000000000000000000000000..57ace0d9669d74f1227331593a958e87c5dfe2a9
--- /dev/null
+++ b/tests/ecb/cherrypick/test2.mod
@@ -0,0 +1,36 @@
+var x y z;
+
+model;
+
+x = y(-1)+z(1);
+
+y = x-z;
+
+diff(z) = 0;
+
+end;
+
+
+if ~isfield(M_, 'exo_names')
+   error('M_.exo_names not defined.')
+end
+
+if ~iscell(M_.exo_names)
+   error('M_.exo_names not a cell array.')
+end
+
+if ~isempty(M_.exo_names)
+   error('M_.exo_names not an empty cell array.')
+end
+
+if ~isfield(M_, 'param_names')
+   error('M_.param_names not defined.')
+end
+
+if ~iscell(M_.param_names)
+   error('M_.param_names not a cell array.')
+end
+
+if ~isempty(M_.param_names)
+   error('M_.param_names not an empty cell array.')
+end
\ No newline at end of file
diff --git a/tests/ecb/contribution-plots/clean b/tests/ecb/contribution-plots/clean
new file mode 100755
index 0000000000000000000000000000000000000000..5546dd8b991350893243592ba0eebf7161ab6e62
--- /dev/null
+++ b/tests/ecb/contribution-plots/clean
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+rm -rf contrib1
+rm -f contrib1.m contrib1_dynamic.m contrib1_set_auxiliary_variables.m contrib1.json contrib1_original.json
+rm -f contrib1_static.json contrib1.log contrib1_dynamic.json contrib1_results.mat contrib1_static.m
+
+rm -rf contrib2
+rm -f contrib2.m contrib2_dynamic.m contrib2_set_auxiliary_variables.m contrib2.json contrib2_original.json
+rm -f contrib2_static.json contrib2.log contrib2_dynamic.json contrib2_results.mat contrib2_static.m
diff --git a/tests/ecb/contribution-plots/contrib1.mod b/tests/ecb/contribution-plots/contrib1.mod
new file mode 100644
index 0000000000000000000000000000000000000000..9b353454989b63bd1312764a5863866021e3909a
--- /dev/null
+++ b/tests/ecb/contribution-plots/contrib1.mod
@@ -0,0 +1,61 @@
+// --+ options: json=compute nostrict +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in a json file (additionaly to the matlab files) which is used here to manipulate the equation
+** of interest.
+*/
+
+// Declaration of the endogenous variables
+var ffr, unrate, cpi;
+
+// Declaration of the exogenous variables
+varexo e_ffr, e_unrate, e_cpi;
+
+
+// Declaration of the model. Note that you must associate a name to the equations. This is mandatory to
+// select the equation for which you need to perform the decomposition.
+model;
+
+[name='ffr']
+     ffr = adl(ffr, 'p_ffr_ffr', [1:3]) + adl(unrate, 'p_ffr_unrate', 1) + adl(cpi, 'p_ffr_cpi', [4]);
+
+[name='unrate']
+     unrate = adl(unrate, 'p_ffr_unrate', [4 2 5]) + adl(cpi, 'p_unrate_cpi', 6);
+
+[name='cpi']
+     cpi = adl(ffr, 'p_cpi_ffr', 2) + adl(cpi, 'p_cpi_cpi', [2]);
+
+end;
+
+// Implicit parameters associated to the adl command must be calibrated after the model block.
+p_ffr_ffr_lag_1 = 1;
+p_ffr_ffr_lag_2 = p_ffr_ffr_lag_1*.5;
+p_ffr_ffr_lag_3 = p_ffr_ffr_lag_2*.5;
+p_ffr_unrate_lag_1 = 2;
+p_ffr_cpi_lag_4 = 3;
+
+// Actual paths for the variables. You migth instead do a stochastic simulation of the model
+// to define these paths.
+ds1 = dseries(randn(30, 3), 1990Q1, {'ffr', 'unrate', 'cpi'});
+
+// Baseline paths for the variables.
+ds0 = dseries(zeros(30, 3), 1990Q1, {'ffr', 'unrate', 'cpi'});
+
+/* Trigger the decomposition in levels of an equation
+**
+** - First argument (ffr) is the name of the equation to be decomposed.
+** - Second argument (ds1) is a dseries object containing the actual paths of the endogenous and exogenous variables.
+** - Third argument (ds0) is a dseries object containing the baseline paths of the endogenous and exogenous variables.
+**
+** If there is no error (missing variables, undefined equations, ...) a figure will pop up with displaying the
+** contributions of the variables appearing on the right hand side of equation `ffr`. Note that the overall contribution
+** of each variable (at all lags) is reported. If you want to decompose these aggregates, you need to rewrite the
+** model as shown in the other mod file in the same folder (contrib2.mod).
+*/
+
+plot_contributions ffr ds1 ds0 ;
diff --git a/tests/ecb/contribution-plots/contrib2.mod b/tests/ecb/contribution-plots/contrib2.mod
new file mode 100644
index 0000000000000000000000000000000000000000..f1fe78b3cba7e346f31954998b114284fbed4b55
--- /dev/null
+++ b/tests/ecb/contribution-plots/contrib2.mod
@@ -0,0 +1,90 @@
+// --+ options: json=compute nostrict +--
+
+/* REMARKS
+** -------
+**
+** Please, firt read the content of contrib1.mod.
+**
+** I consider the same model as in contrib1.mod, but here we want to obtain the contributions of
+** the variables to `ffr` at all lags (individually). To do this we need to add variables for all
+** the lags, add corresponding equations (defining the new variables) and add the new variables
+** in the dseries objects.
+*/
+
+// Declaration of the endogenous variables
+var ffr, unrate, cpi;
+
+// Define additional variables
+var ffr_lag_1, ffr_lag_2, ffr_lag_3, unrate_lag_1, cpi_lag_4;
+
+// Declaration of the exogenous variables
+varexo e_ffr, e_unrate, e_cpi;
+
+
+// Declare the parameters appearing in the equation to be decomposed.
+parameters p_ffr_ffr_lag_1 p_ffr_ffr_lag_2 p_ffr_ffr_lag_3 p_ffr_unrate_lag_1 p_ffr_cpi_lag_4;
+
+// Declaration of the model. Note that you must associate a name to the equations. This is mandatory to
+// select the equation for which you need to perform the decomposition.
+model;
+
+[name='ffr']
+     //ffr = adl(ffr, 'p_ffr_ffr', [1:3]) + adl(unrate, 'p_ffr_unrate', 1) + adl(cpi, 'p_ffr_cpi', [4]);
+     ffr = p_ffr_ffr_lag_1*ffr_lag_1 + p_ffr_ffr_lag_2*ffr_lag_2 + p_ffr_ffr_lag_3*ffr_lag_3
+           + p_ffr_unrate_lag_1*unrate_lag_1
+           + p_ffr_cpi_lag_4*cpi_lag_4;
+
+[name='unrate']
+     unrate = adl(unrate, 'p_ffr_unrate', [4 2 5]) + adl(cpi, 'p_unrate_cpi', 6);
+
+[name='cpi']
+     cpi = adl(ffr, 'p_cpi_ffr', 2) + adl(cpi, 'p_cpi_cpi', [2]);
+
+// Definitions of the auxiliary variables (we don't need names for these equations).
+ffr_lag_1 = ffr(-1);
+ffr_lag_2 = ffr(-2);
+ffr_lag_3 = ffr(-3);
+unrate_lag_1 = unrate(-1);
+cpi_lag_4 = cpi(-4);
+
+end;
+
+// Implicit parameters associated to the adl command must be calibrated after the model block.
+p_ffr_ffr_lag_1 = 1;
+p_ffr_ffr_lag_2 = p_ffr_ffr_lag_1*.5;
+p_ffr_ffr_lag_3 = p_ffr_ffr_lag_2*.5;
+p_ffr_unrate_lag_1 = 2;
+p_ffr_cpi_lag_4 = 3;
+
+// Actual paths for the variables. You migth instead do a stochastic simulation of the model
+// to define these paths.
+ds1 = dseries(randn(30, 3), 1990Q1, {'ffr', 'unrate', 'cpi'});
+
+// Create auxiliary variables as dseries objects
+verbatim;
+
+  ffr_lag_1 = dseries(ds1.ffr(-1).data, ds1.firstdate, 'ffr_lag_1');
+  ffr_lag_2 = dseries(ds1.ffr(-2).data, ds1.firstdate, 'ffr_lag_2');
+  ffr_lag_3 = dseries(ds1.ffr(-3).data, ds1.firstdate, 'ffr_lag_3');
+  unrate_lag_1 = dseries(ds1.unrate(-1).data, ds1.firstdate, 'unrate_lag_1');
+  cpi_lag_4 = dseries(ds1.cpi(-4).data, ds1.firstdate, 'cpi_lag_4');
+
+end;
+
+// Put them in ds1
+ds1 = [ds1, ffr_lag_1, ffr_lag_2, ffr_lag_3, unrate_lag_1, cpi_lag_4];
+
+// Baseline paths for the variables.
+ds0 = dseries(zeros(30, 8), 1990Q1, {'ffr', 'unrate', 'cpi', 'ffr_lag_1', 'ffr_lag_2', 'ffr_lag_3', 'unrate_lag_1', 'cpi_lag_4'});
+
+/* Trigger the decomposition in levels of an equation
+**
+** - First argument (ffr) is the name of the equation to be decomposed.
+** - Second argument (ds1) is a dseries object containing the actual paths of the endogenous and exogenous variables.
+** - Third argument (ds0) is a dseries object containing the baseline paths of the endogenous and exogenous variables.
+**
+** If there is no error (missing variables, undefined equations, ...) a figure will pop up with displaying the
+** contributions of the variables appearing on the right hand side of equation `ffr`.
+*/
+
+plot_contributions ffr ds1 ds0 ;
diff --git a/tests/ecb/panel_var/panel_var_diff.mod b/tests/ecb/panel_var/panel_var_diff.mod
new file mode 100644
index 0000000000000000000000000000000000000000..a948b37f66a5c406d024750a00e4490a5da4c9d1
--- /dev/null
+++ b/tests/ecb/panel_var/panel_var_diff.mod
@@ -0,0 +1,346 @@
+// --+ options: json=compute +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+FR_Q_YED
+FR_G_YER
+FR_EHIC
+IT_Q_YED
+IT_G_YER
+IT_EHIC
+ES_Q_YED
+ES_G_YER
+ES_EHIC
+NL_Q_YED
+NL_G_YER
+NL_EHIC
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+res_FR_Q_YED
+res_FR_G_YER
+res_FR_EHIC
+res_IT_Q_YED
+res_IT_G_YER
+res_IT_EHIC
+res_ES_Q_YED
+res_ES_G_YER
+res_ES_EHIC
+res_NL_Q_YED
+res_NL_G_YER
+res_NL_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_g_yer_u2_stn_L1
+de_ehic_de_ehic_L1
+
+fr_q_yed_ecm_fr_q_yed_L1
+fr_q_yed_ecm_u2_stn_L1
+fr_q_yed_fr_g_yer_L1
+fr_q_yed_u2_stn_L1
+fr_g_yer_ecm_fr_q_yed_L1
+fr_g_yer_ecm_u2_stn_L1
+fr_g_yer_fr_q_yed_L1
+fr_g_yer_fr_g_yer_L1
+fr_g_yer_u2_stn_L1
+fr_ehic_fr_ehic_L1
+
+it_q_yed_ecm_it_q_yed_L1
+it_q_yed_ecm_u2_stn_L1
+it_q_yed_it_g_yer_L1
+it_q_yed_u2_stn_L1
+it_g_yer_ecm_it_q_yed_L1
+it_g_yer_ecm_u2_stn_L1
+it_g_yer_it_q_yed_L1
+it_g_yer_it_g_yer_L1
+it_g_yer_u2_stn_L1
+it_ehic_it_ehic_L1
+
+es_q_yed_ecm_es_q_yed_L1
+es_q_yed_ecm_u2_stn_L1
+es_q_yed_es_g_yer_L1
+es_q_yed_u2_stn_L1
+es_g_yer_ecm_es_q_yed_L1
+es_g_yer_ecm_u2_stn_L1
+es_g_yer_es_q_yed_L1
+es_g_yer_es_g_yer_L1
+es_g_yer_u2_stn_L1
+es_ehic_es_ehic_L1
+
+nl_q_yed_ecm_nl_q_yed_L1
+nl_q_yed_ecm_u2_stn_L1
+nl_q_yed_nl_g_yer_L1
+nl_q_yed_u2_stn_L1
+nl_g_yer_ecm_nl_q_yed_L1
+nl_g_yer_ecm_u2_stn_L1
+nl_g_yer_nl_q_yed_L1
+nl_g_yer_nl_g_yer_L1
+nl_g_yer_u2_stn_L1
+nl_ehic_nl_ehic_L1
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+fr_q_yed_ecm_fr_q_yed_L1  = -0.822375165893149  ;
+fr_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+fr_q_yed_fr_g_yer_L1      =  0.0401361895021082 ;
+fr_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+fr_g_yer_ecm_fr_q_yed_L1  =  0.0189896046977422 ;
+fr_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+fr_g_yer_fr_q_yed_L1      =  0.00376679676320256;
+fr_g_yer_fr_g_yer_L1      =  0.480506381923643  ;
+fr_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+fr_ehic_fr_ehic_L1        =  1                  ;
+
+it_q_yed_ecm_it_q_yed_L1  = -0.822375165893149  ;
+it_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+it_q_yed_it_g_yer_L1      =  0.0401361895021082 ;
+it_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+it_g_yer_ecm_it_q_yed_L1  =  0.0189896046977422 ;
+it_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+it_g_yer_it_q_yed_L1      =  0.00376679676320256;
+it_g_yer_it_g_yer_L1      =  0.480506381923643  ;
+it_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+it_ehic_it_ehic_L1        =  1                  ;
+
+es_q_yed_ecm_es_q_yed_L1  = -0.822375165893149  ;
+es_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+es_q_yed_es_g_yer_L1      =  0.0401361895021082 ;
+es_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+es_g_yer_ecm_es_q_yed_L1  =  0.0189896046977422 ;
+es_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+es_g_yer_es_q_yed_L1      =  0.00376679676320256;
+es_g_yer_es_g_yer_L1      =  0.480506381923643  ;
+es_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+es_ehic_es_ehic_L1        =  1                  ;
+
+nl_q_yed_ecm_nl_q_yed_L1  = -0.822375165893149  ;
+nl_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+nl_q_yed_nl_g_yer_L1      =  0.0401361895021082 ;
+nl_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+nl_g_yer_ecm_nl_q_yed_L1  =  0.0189896046977422 ;
+nl_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+nl_g_yer_nl_q_yed_L1      =  0.00376679676320256;
+nl_g_yer_nl_g_yer_L1      =  0.480506381923643  ;
+nl_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+nl_ehic_nl_ehic_L1        =  1                  ;
+
+
+model;
+
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN
+                 + res_U2_ESTN                                            ;
+
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC
+                 + res_U2_EHIC                                            ;
+
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+
+DE_EHIC        =   de_ehic_de_ehic_L1       * DE_EHIC
+                 + res_DE_EHIC                                            ;
+
+diff(FR_Q_YED) =   fr_q_yed_ecm_fr_q_yed_L1 * (FR_Q_YED(-1) - FR_EHIC(-1))
+                 + fr_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + fr_q_yed_fr_g_yer_L1     * diff(FR_G_YER(-1))
+                 + fr_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_FR_Q_YED                                           ;
+
+diff(FR_G_YER) =   fr_g_yer_ecm_fr_q_yed_L1 * (FR_Q_YED(-1) - FR_EHIC(-1))
+                 + fr_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + fr_g_yer_fr_q_yed_L1     * diff(FR_Q_YED(-1))
+                 + fr_g_yer_fr_g_yer_L1     * diff(FR_G_YER(-1))
+                 + fr_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_FR_G_YER                                           ;
+
+FR_EHIC        =   fr_ehic_fr_ehic_L1       * FR_EHIC
+                 + res_FR_EHIC                                            ;
+
+diff(IT_Q_YED) =   it_q_yed_ecm_it_q_yed_L1 * (IT_Q_YED(-1) - IT_EHIC(-1))
+                 + it_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + it_q_yed_it_g_yer_L1     * diff(IT_G_YER(-1))
+                 + it_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_IT_Q_YED                                           ;
+
+diff(IT_G_YER) =   it_g_yer_ecm_it_q_yed_L1 * (IT_Q_YED(-1) - IT_EHIC(-1))
+                 + it_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + it_g_yer_it_q_yed_L1     * diff(IT_Q_YED(-1))
+                 + it_g_yer_it_g_yer_L1     * diff(IT_G_YER(-1))
+                 + it_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_IT_G_YER                                           ;
+
+IT_EHIC        =   it_ehic_it_ehic_L1       * IT_EHIC
+                 + res_IT_EHIC                                            ;
+
+diff(ES_Q_YED) =   es_q_yed_ecm_es_q_yed_L1 * (ES_Q_YED(-1) - ES_EHIC(-1))
+                 + es_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + es_q_yed_es_g_yer_L1     * diff(ES_G_YER(-1))
+                 + es_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_ES_Q_YED                                           ;
+
+diff(ES_G_YER) =   es_g_yer_ecm_es_q_yed_L1 * (ES_Q_YED(-1) - ES_EHIC(-1))
+                 + es_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + es_g_yer_es_q_yed_L1     * diff(ES_Q_YED(-1))
+                 + es_g_yer_es_g_yer_L1     * diff(ES_G_YER(-1))
+                 + es_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_ES_G_YER                                           ;
+
+ES_EHIC        =   es_ehic_es_ehic_L1       * ES_EHIC
+                 + res_ES_EHIC                                            ;
+
+diff(NL_Q_YED) =   nl_q_yed_ecm_nl_q_yed_L1 * (NL_Q_YED(-1) - NL_EHIC(-1))
+                 + nl_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + nl_q_yed_nl_g_yer_L1     * diff(NL_G_YER(-1))
+                 + nl_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_NL_Q_YED                                           ;
+
+diff(NL_G_YER) =   nl_g_yer_ecm_nl_q_yed_L1 * (NL_Q_YED(-1) - NL_EHIC(-1))
+                 + nl_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + nl_g_yer_nl_q_yed_L1     * diff(NL_Q_YED(-1))
+                 + nl_g_yer_nl_g_yer_L1     * diff(NL_G_YER(-1))
+                 + nl_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_NL_G_YER                                           ;
+
+NL_EHIC        =   nl_ehic_nl_ehic_L1       * NL_EHIC
+                 + res_NL_EHIC                                            ;
+
+
+end;
+
+mydseries = dseries(randn(40,20), 1, {'U2_Q_YED', ...
+                                      'U2_G_YER', ...
+                                      'U2_STN', ...
+                                      'U2_ESTN', ...
+                                      'U2_EHIC', ...
+                                      'DE_Q_YED', ...
+                                      'DE_G_YER', ...
+                                      'DE_EHIC', ...
+                                      'FR_Q_YED', ...
+                                      'FR_G_YER', ...
+                                      'FR_EHIC', ...
+                                      'IT_Q_YED', ...
+                                      'IT_G_YER', ...
+                                      'IT_EHIC', ...
+                                      'ES_Q_YED', ...
+                                      'ES_G_YER', ...
+                                      'ES_EHIC', ...
+                                      'NL_Q_YED', ...
+                                      'NL_G_YER', ...
+                                      'NL_EHIC'});
+
+pooled_ols(mydseries, ...
+           {'de','u2','fr', 'it', 'es', 'nl'}, ...
+           {'*_q_yed_ecm_*_q_yed_L1', ...
+            '*_q_yed_ecm_u2_stn_L1', ...
+            '*_q_yed_*_g_yer_L1', ...
+            '*_q_yed_u2_stn_L1', ...
+            '*_g_yer_ecm_*_q_yed_L1', ...
+            '*_g_yer_ecm_u2_stn_L1', ...
+            '*_g_yer_*_q_yed_L1', ...
+            '*_g_yer_*_g_yer_L1', ...
+            '*_g_yer_u2_stn_L1', ...
+            '*_ehic_*_ehic_L1'});
diff --git a/tests/ecb/panel_var/panel_var_diff_NB_2country.mod b/tests/ecb/panel_var/panel_var_diff_NB_2country.mod
new file mode 100755
index 0000000000000000000000000000000000000000..6108267434784ad30a653bf6c4073e68f1b349e3
--- /dev/null
+++ b/tests/ecb/panel_var/panel_var_diff_NB_2country.mod
@@ -0,0 +1,147 @@
+// --+ options: json=compute +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_g_yer_u2_stn_L1
+de_ehic_de_ehic_L1
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model;
+
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+
+DE_EHIC        =   de_ehic_de_ehic_L1       * DE_EHIC(-1)
+                 + res_DE_EHIC                                            ;
+
+end;
+
+pooled_fgls(dseries('data_var.mat'), ...
+           {'de','u2'}, ...
+           {'*_q_yed_ecm_*_q_yed_L1', ...
+            '*_q_yed_ecm_u2_stn_L1', ...
+            '*_q_yed_*_g_yer_L1', ...
+            '*_q_yed_u2_stn_L1', ...
+            '*_g_yer_ecm_*_q_yed_L1', ...
+            '*_g_yer_ecm_u2_stn_L1', ...
+            '*_g_yer_*_q_yed_L1', ...
+            '*_g_yer_*_g_yer_L1', ...
+            '*_g_yer_u2_stn_L1', ...
+            '*_ehic_*_ehic_L1'});
diff --git a/tests/ecb/partial-estimation/clean b/tests/ecb/partial-estimation/clean
new file mode 100755
index 0000000000000000000000000000000000000000..d811f5ce5f588442d62b5f59cceefb5f14e04750
--- /dev/null
+++ b/tests/ecb/partial-estimation/clean
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+rm -rf estimation_of_a_single_equation
+rm -f *.json *.m *.mat *.log
\ No newline at end of file
diff --git a/tests/ecb/partial-estimation/estimation_of_a_single_equation.mod b/tests/ecb/partial-estimation/estimation_of_a_single_equation.mod
new file mode 100644
index 0000000000000000000000000000000000000000..8358725a8e31ce3a48d19478c6e295be3d71b0d0
--- /dev/null
+++ b/tests/ecb/partial-estimation/estimation_of_a_single_equation.mod
@@ -0,0 +1,60 @@
+// --+ options: json=compute +--
+
+// Declare the endogenous variables.
+var ffr, unrate, cpi;
+
+// Declare the exogenous variables.
+varexo e_ffr, e_unrate, e_cpi;
+
+// Declare the model.
+model(linear);
+
+[name='ffr']
+     ffr = adl(ffr, 'p_ffr_ffr', [1:3]) + adl(unrate, 'p_ffr_unrate', 1) + adl(cpi, 'p_ffr_cpi', [4]) + e_ffr;
+
+[name='unrate']
+     unrate = adl(unrate, 'p_ffr_unrate', [4 2 5]) + adl(cpi, 'p_unrate_cpi', 6) + e_unrate;
+
+[name='cpi']
+     cpi = adl(ffr, 'p_cpi_ffr', 2) + adl(cpi, 'p_cpi_cpi', [2]) + e_cpi;
+
+end;
+
+// Set true values for the parameters (randomly, I write directly in M_.params
+// because I am too lazy to write all the parameter names).
+M_.params = .1*randn(M_.param_nbr, 1);
+
+shocks;
+var e_ffr; stderr .01;
+var e_unrate; stderr .01;
+var e_cpi; stderr .01;
+end;
+
+// Create a dataset by simulating the model.
+oo_ = simul_backward_model([], 1000, options_, M_, oo_);
+
+// Put all the simulated data in a dseries object.
+ds1 = dseries(transpose(oo_.endo_simul), 1900Q1, M_.endo_names);
+
+
+// Select a subsample for estimation
+ds1 = ds1(1951Q1:1990Q1);
+
+
+// Print true values of the parameters (for comparison with the estimation results).
+dyn_table('True values for the parameters (DGP)', {}, {}, cellstr(M_.param_names), ...
+    {'Parameter Value'}, 4, M_.params);
+
+
+/* Run the estimation of equation ffr and display the results. Note that the corresponding
+** values in M_.params will be updated.
+**
+** estimate command
+** ----------------
+**
+** First argument is used to specify the estimation method
+** Second argument is used to specify the dataset (an existing dseries object).
+** Third argument (and following) is(are) the name(s) of equation(s) to be estimated.
+*/
+
+estimate method(ols) data(ds1) ffr;
diff --git a/tests/ecb/pooled_fgls/panel_var_diff_NB_simulation_test.mod b/tests/ecb/pooled_fgls/panel_var_diff_NB_simulation_test.mod
new file mode 100644
index 0000000000000000000000000000000000000000..c36a2a5d4b0c927bf5a8bdf8c6d9c2954d00119a
--- /dev/null
+++ b/tests/ecb/pooled_fgls/panel_var_diff_NB_simulation_test.mod
@@ -0,0 +1,235 @@
+// --+ options: json=compute +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_g_yer_u2_stn_L1
+de_ehic_de_ehic_L1
+
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        =   de_ehic_de_ehic_L1       * DE_EHIC(-1)
+                 + res_DE_EHIC                                            ;
+
+
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+NSIMS = 1;
+
+calibrated_values = M_.params;
+verbatim;
+Sigma_e = M_.Sigma_e;
+end;
+
+options_.bnlms.set_dynare_seed_to_default = false;
+
+nparampool = length(M_.params);
+BETA = zeros(NSIMS, nparampool);
+for i=1:NSIMS
+    firstobs = rand(3, length(M_.endo_names));
+    M_.params = calibrated_values;
+    M_.Sigma_e = Sigma_e; 
+    simdata = simul_backward_model(dseries(firstobs, dates('1995Q1'), M_.endo_names), 10000);
+    simdata = simdata(simdata.dates(5001:6000));
+    names=regexp(simdata.name, 'res\w*');
+    idxs = [];
+    for j=1:length(names)
+        if isempty(names{j})
+            idxs = [idxs j];
+        end
+    end
+    pooled_fgls(simdata{idxs}, ...
+        {'de','u2'}, ...
+        {'*_q_yed_ecm_*_q_yed_L1', ...
+        '*_q_yed_ecm_u2_stn_L1', ...
+        '*_q_yed_*_g_yer_L1', ...
+        '*_q_yed_u2_stn_L1', ...
+        '*_g_yer_ecm_*_q_yed_L1', ...
+        '*_g_yer_ecm_u2_stn_L1', ...
+        '*_g_yer_*_q_yed_L1', ...
+        '*_g_yer_*_g_yer_L1', ...
+        '*_g_yer_u2_stn_L1', ...
+        '*_ehic_*_ehic_L1'});
+    BETA(i, :) = M_.params';
+    oo_ = rmfield(oo_, 'pooled_fgls');
+end
+
+if NSIMS > 1
+    if sum(abs(mean(BETA)' - calibrated_values)) > 1e-2
+        error(['sum(abs(mean(BETA)'' - calibrated_values)) ' num2str(sum(abs(mean(BETA)' - calibrated_values)))]);
+    end
+else
+    good = [-0.814463611096955
+        -0.327545854281441
+        0.058155751549620
+        0.056956172127541
+        0.004760467203543
+        -0.110209140210870
+        0.000873625473015
+        0.492984603730353
+        -0.110739844810764
+        -0.026953553332579
+        -0.155433250333810
+        0.053391289583053
+        0.275361374992940
+        1.000446511792020
+        0.999278815424852
+        -0.814463611096955
+        -0.327545854281441
+        0.058155751549620
+        0.056956172127541
+        0.004760467203543
+        -0.110209140210870
+        0.000873625473015
+        0.492984603730353
+        -0.110739844810764
+        0.999278815424852];
+    if max(abs(BETA' - good)) > 1e-14
+        error(['sum of BETA'' - good was: ' num2str(sum(abs(BETA - good)))]);
+    end
+    return
+end
+
+for i=1:nparampool
+    figure
+    hold on
+    title(strrep(M_.param_names(i,:), '_', '\_'));
+    histogram(BETA(:,i),50);
+    line([calibrated_values(i) calibrated_values(i)], [0 NSIMS/10], 'LineWidth', 2, 'Color', 'r');
+    hold off
+end
diff --git a/tests/ecb/pooled_fgls/test_param_names.mod b/tests/ecb/pooled_fgls/test_param_names.mod
new file mode 100644
index 0000000000000000000000000000000000000000..cc76ee1497cc69c75017e4cf7596592579a495b5
--- /dev/null
+++ b/tests/ecb/pooled_fgls/test_param_names.mod
@@ -0,0 +1,240 @@
+// --+ options: json=compute +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_g_yer_u2_stn_L1
+de_ehic_de_ehic_L1
+
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        =   de_ehic_de_ehic_L1       * DE_EHIC(-1)
+                 + res_DE_EHIC                                            ;
+
+
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+NSIMS = 1;
+
+calibrated_values = M_.params;
+verbatim;
+Sigma_e = M_.Sigma_e;
+end;
+
+options_.bnlms.set_dynare_seed_to_default = false;
+
+nparampool = length(M_.params);
+BETA = zeros(NSIMS, nparampool);
+for i=1:NSIMS
+    firstobs = rand(3, length(M_.endo_names));
+    M_.params = calibrated_values;
+    M_.Sigma_e = Sigma_e; 
+    simdata = simul_backward_model(dseries(firstobs, dates('1995Q1'), M_.endo_names), 10000);
+    simdata = simdata(simdata.dates(5001:6000));
+    names=regexp(simdata.name, 'res\w*');
+    idxs = [];
+    for j=1:length(names)
+        if isempty(names{j})
+            idxs = [idxs j];
+        end
+    end
+    pooled_fgls(simdata{idxs}, ...
+        {'de','u2'}, ...
+        {'*_q_yed_ecm_*_q_yed_L1', ...
+        '*_q_yed_ecm_u2_stn_L1', ...
+        '*_q_yed_*_g_yer_L1', ...
+        '*_q_yed_u2_stn_L1', ...
+        '*_g_yer_ecm_*_q_yed_L1', ...
+        '*_g_yer_ecm_u2_stn_L1', ...
+        '*_g_yer_*_q_yed_L1', ...
+        '*_g_yer_*_g_yer_L1', ...
+        '*_g_yer_u2_stn_L1'}, ...
+        {}, '', ...
+        {'*_q_yed_ecm_*_q_yed_L1', ...
+        '*_q_yed_ecm_u2_stn_L1', ...
+        '*_q_yed_*_g_yer_L1', ...
+        '*_q_yed_u2_stn_L1', ...
+        'de_ehic_de_ehic_L1'});
+    BETA(i, :) = M_.params';
+    oo_ = rmfield(oo_, 'pooled_fgls');
+end
+
+if NSIMS > 1
+    if max(abs(mean(BETA)' - calibrated_values)) > 1e-2
+        error(['sum(abs(mean(BETA)'' - calibrated_values)) ' num2str(sum(abs(mean(BETA)' - calibrated_values)))]);
+    end
+else
+    good = [-0.814720065821038
+        -0.327476517170325
+        0.058494818795786
+        0.057190907485572
+        0.018989604697742
+        -0.109597659887432
+        0.003766796763203
+        0.480506381923644
+        -0.072235928612349
+        -0.043850066260836
+        -0.153283917138772
+        0.032874498377282
+        0.292121949736756
+        1.000000000000000
+        1.000000000000000
+        -0.814720065821038
+        -0.327476517170325
+        0.058494818795786
+        0.057190907485572
+        0.018989604697742
+        -0.109597659887433
+        0.003766796763203
+        0.480506381923643
+        -0.072235928612349
+        0.999222744717732];
+    if max(abs(BETA' - good)) > 1e-14
+        error(['sum of BETA'' - good was: ' num2str(sum(abs(BETA - good)))]);
+    end
+    return
+end
+
+for i=1:nparampool
+    figure
+    hold on
+    title(strrep(M_.param_names(i,:), '_', '\_'));
+    histogram(BETA(:,i),50);
+    line([calibrated_values(i) calibrated_values(i)], [0 NSIMS/10], 'LineWidth', 2, 'Color', 'r');
+    hold off
+end
diff --git a/tests/ecb/pooled_ols/panel_var_diff_NB_simulation_test.mod b/tests/ecb/pooled_ols/panel_var_diff_NB_simulation_test.mod
new file mode 100644
index 0000000000000000000000000000000000000000..bed845401f72ac559088a38c88e48ea2601c821c
--- /dev/null
+++ b/tests/ecb/pooled_ols/panel_var_diff_NB_simulation_test.mod
@@ -0,0 +1,235 @@
+// --+ options: json=compute +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_g_yer_u2_stn_L1
+de_ehic_de_ehic_L1
+
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        =   de_ehic_de_ehic_L1       * DE_EHIC(-1)
+                 + res_DE_EHIC                                            ;
+
+
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+NSIMS = 1;
+
+calibrated_values = M_.params;
+verbatim;
+Sigma_e = M_.Sigma_e;
+end;
+
+options_.bnlms.set_dynare_seed_to_default = false;
+
+nparampool = length(M_.params);
+BETA = zeros(NSIMS, nparampool);
+for i=1:NSIMS
+    firstobs = rand(3, length(M_.endo_names));
+    M_.params = calibrated_values;
+    M_.Sigma_e = Sigma_e; 
+    simdata = simul_backward_model(dseries(firstobs, dates('1995Q1'), M_.endo_names), 10000);
+    simdata = simdata(simdata.dates(5001:6000));
+    names=regexp(simdata.name, 'res\w*');
+    idxs = [];
+    for j=1:length(names)
+        if isempty(names{j})
+            idxs = [idxs j];
+        end
+    end
+    pooled_ols(simdata{idxs}, ...
+        {'de','u2'}, ...
+        {'*_q_yed_ecm_*_q_yed_L1', ...
+        '*_q_yed_ecm_u2_stn_L1', ...
+        '*_q_yed_*_g_yer_L1', ...
+        '*_q_yed_u2_stn_L1', ...
+        '*_g_yer_ecm_*_q_yed_L1', ...
+        '*_g_yer_ecm_u2_stn_L1', ...
+        '*_g_yer_*_q_yed_L1', ...
+        '*_g_yer_*_g_yer_L1', ...
+        '*_g_yer_u2_stn_L1', ...
+        '*_ehic_*_ehic_L1'});
+    BETA(i, :) = M_.params';
+    oo_ = rmfield(oo_, 'pooled_ols');
+end
+
+if NSIMS > 1
+    if sum(abs(mean(BETA)' - calibrated_values)) > 1e-2
+        error(['sum(abs(mean(BETA)'' - calibrated_values)) ' num2str(sum(abs(mean(BETA)' - calibrated_values)))]);
+    end
+else
+    good = [-0.814685080218300
+        -0.327809964140588
+        0.058359966460475
+        0.056151094599907
+        0.004707755717058
+        -0.110288651670160
+        0.000910770641800
+        0.494342669441397
+        -0.109455922483561
+        -0.029329632163194
+        -0.157236653586389
+        0.054467548349538
+        0.275969658826900
+        1.000451016087141
+        0.999236021952814
+        -0.814685080218300
+        -0.327809964140588
+        0.058359966460475
+        0.056151094599907
+        0.004707755717058
+        -0.110288651670160
+        0.000910770641800
+        0.494342669441397
+        -0.109455922483561
+        0.999236021952814];
+    if max(abs(BETA' - good)) > 1e-14
+        error(['sum of BETA'' - good was: ' num2str(sum(abs(BETA - good)))]);
+    end
+    return
+end
+
+for i=1:nparampool
+    figure
+    hold on
+    title(strrep(M_.param_names(i,:), '_', '\_'));
+    histogram(BETA(:,i),50);
+    line([calibrated_values(i) calibrated_values(i)], [0 NSIMS/10], 'LineWidth', 2, 'Color', 'r');
+    hold off
+end
diff --git a/tests/ecb/pooled_ols/test_param_names.mod b/tests/ecb/pooled_ols/test_param_names.mod
new file mode 100644
index 0000000000000000000000000000000000000000..fad39e7e5deb22d762eabe069013fc9246ab82ba
--- /dev/null
+++ b/tests/ecb/pooled_ols/test_param_names.mod
@@ -0,0 +1,240 @@
+// --+ options: json=compute +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_g_yer_u2_stn_L1
+de_ehic_de_ehic_L1
+
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        =   de_ehic_de_ehic_L1       * DE_EHIC(-1)
+                 + res_DE_EHIC                                            ;
+
+
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+NSIMS = 1;
+
+calibrated_values = M_.params;
+verbatim;
+Sigma_e = M_.Sigma_e;
+end;
+
+options_.bnlms.set_dynare_seed_to_default = false;
+
+nparampool = length(M_.params);
+BETA = zeros(NSIMS, nparampool);
+for i=1:NSIMS
+    firstobs = rand(3, length(M_.endo_names));
+    M_.params = calibrated_values;
+    M_.Sigma_e = Sigma_e; 
+    simdata = simul_backward_model(dseries(firstobs, dates('1995Q1'), M_.endo_names), 10000);
+    simdata = simdata(simdata.dates(5001:6000));
+    names=regexp(simdata.name, 'res\w*');
+    idxs = [];
+    for j=1:length(names)
+        if isempty(names{j})
+            idxs = [idxs j];
+        end
+    end
+    pooled_ols(simdata{idxs}, ...
+        {'de','u2'}, ...
+        {'*_q_yed_ecm_*_q_yed_L1', ...
+        '*_q_yed_ecm_u2_stn_L1', ...
+        '*_q_yed_*_g_yer_L1', ...
+        '*_q_yed_u2_stn_L1', ...
+        '*_g_yer_ecm_*_q_yed_L1', ...
+        '*_g_yer_ecm_u2_stn_L1', ...
+        '*_g_yer_*_q_yed_L1', ...
+        '*_g_yer_*_g_yer_L1', ...
+        '*_g_yer_u2_stn_L1'}, ...
+        false, {}, '', ...
+        {'*_q_yed_ecm_*_q_yed_L1', ...
+        '*_q_yed_ecm_u2_stn_L1', ...
+        '*_q_yed_*_g_yer_L1', ...
+        '*_q_yed_u2_stn_L1', ...
+        'de_ehic_de_ehic_L1'});
+    BETA(i, :) = M_.params';
+    oo_ = rmfield(oo_, 'pooled_ols');
+end
+
+if NSIMS > 1
+    if max(abs(mean(BETA)' - calibrated_values)) > 1e-2
+        error(['sum(abs(mean(BETA)'' - calibrated_values)) ' num2str(sum(abs(mean(BETA)' - calibrated_values)))]);
+    end
+else
+    good = [-0.814685080218300
+        -0.327809964140588
+        0.058359966460474
+        0.056151094599907
+        0.018989604697742
+        -0.109597659887432
+        0.003766796763203
+        0.480506381923644
+        -0.072235928612349
+        -0.043850066260836
+        -0.153283917138772
+        0.032874498377282
+        0.292121949736756
+        1.000000000000000
+        1.000000000000000
+        -0.814685080218300
+        -0.327809964140588
+        0.058359966460474
+        0.056151094599907
+        0.018989604697742
+        -0.109597659887433
+        0.003766796763203
+        0.480506381923643
+        -0.072235928612349
+        0.999158727555345];
+    if max(abs(BETA' - good)) > 1e-14
+        error(['sum of BETA'' - good was: ' num2str(sum(abs(BETA - good)))]);
+    end
+    return
+end
+
+for i=1:nparampool
+    figure
+    hold on
+    title(strrep(M_.param_names(i,:), '_', '\_'));
+    histogram(BETA(:,i),50);
+    line([calibrated_values(i) calibrated_values(i)], [0 NSIMS/10], 'LineWidth', 2, 'Color', 'r');
+    hold off
+end
diff --git a/tests/estimation/univariate/bayesian.mod b/tests/estimation/univariate/bayesian.mod
new file mode 100644
index 0000000000000000000000000000000000000000..d5dcce24f7dc3616e9a69e567acac0f2642dbe07
--- /dev/null
+++ b/tests/estimation/univariate/bayesian.mod
@@ -0,0 +1,68 @@
+// --+ options: json=compute +--
+// https://www3.nd.edu/~rwilliam/stats1/OLS-Stata9.pdf
+
+var income educ jobexp race;
+
+varexo e;
+
+parameters b1, b2, b3, b4;
+
+model;
+
+ // The following three lines are required because the variables are declared as endogenous, but the equations
+ // have no consequences on the estimation of the last equation in the block.
+ educ = educ;
+ jobexp = jobexp;
+ race = race;
+
+ [name='eqols']
+ income = b1 + b2*educ + b3*jobexp + b4*race + e;
+
+end;
+
+// Load data.
+ds = dseries('data.csv');
+
+// Estimate last equatioon by OLS (ds is updated with the fitted values).
+ds = dyn_ols(ds, {}, {'eqols'});
+
+/*
+** BAYESIAN ESTIMATION OF 'eqols'
+*/
+
+// Set the number of estimated parameters.
+n = length(oo_.ols.eqols.beta);
+
+// We consider a kind of non informative prior by assuming that the inverse of the prior variance for β is zero.
+V0 = diag(Inf(n, 1));
+
+// We choose the prior mean for β randomly (around the OLS estimate).
+beta0 = oo_.ols.eqols.beta + randn(n, 1); 
+
+// Set prior for the variance of the error
+s2priormean = 17;
+s2df = 1;
+
+// Run bayesian estimation with normal-gamma prior. Because there is no closed
+// form expression for the joint posterior marginal distribution of β, a Gibbs
+// sampling algorithm is used (the prior for β and the inverse of σ² are independent).
+
+gibbslength = 1000000; // Set the number of iterations in Gibbs 
+burnin = 10000;        // Set the number of iterations to be discarded (try to remove the effects of the initial condition).
+steps = 10;            // Do not record all iterations (try to remove the dependence between the draws).
+
+ds = olsgibbs(ds, 'eqols', beta0, V0, s2priormean, s2df, gibbslength, burnin, steps, {'eqols', 'eqols_olsgibbs_fit'});
+
+// Since we use a diffuse prior for β, the posterior mean of β should be close to the OLS estimate.
+if max(abs(oo_.ols.eqols.beta-oo_.olsgibbs.eqols.posterior.mean.beta))>.1
+   error('Something is wrong in the Gibbs sampling routine (univariate model)')
+end
+
+// We can plot the posterior distribution of the parameters:
+post = oo_.olsgibbs.eqols.posterior.density.b2;
+plot(post(:,1), post(:,2), '-k', 'linewidth', 2);
+axis tight
+box on
+hold on
+plot([oo_.olsgibbs.eqols.posterior.mean.beta(2), oo_.olsgibbs.eqols.posterior.mean.beta(2)], [0 max(post(:,2))], '-r')
+hold off
\ No newline at end of file
diff --git a/tests/estimation/univariate/bayesian_param_names.mod b/tests/estimation/univariate/bayesian_param_names.mod
new file mode 100644
index 0000000000000000000000000000000000000000..54e042a08cb7ec01a604fc3f38a690e3281c8c57
--- /dev/null
+++ b/tests/estimation/univariate/bayesian_param_names.mod
@@ -0,0 +1,71 @@
+// --+ options: json=compute +--
+// https://www3.nd.edu/~rwilliam/stats1/OLS-Stata9.pdf
+
+var income educ jobexp race;
+
+varexo e;
+
+parameters b1, b2, b3, b4;
+
+b1 = 0.1;
+b4 = 0.2;
+
+model;
+
+ // The following three lines are required because the variables are declared as endogenous, but the equations
+ // have no consequences on the estimation of the last equation in the block.
+ educ = educ;
+ jobexp = jobexp;
+ race = race;
+
+ [name='eqols']
+ income = b1 + b2*educ + b3*jobexp + b4*race + e;
+
+end;
+
+// Load data.
+ds = dseries('data.csv');
+
+// Estimate last equatioon by OLS (ds is updated with the fitted values).
+ds = dyn_ols(ds, {}, {'eqols'}, {'ols_eq'}, {{'b2'; 'b3'}});
+
+/*
+** BAYESIAN ESTIMATION OF 'eqols'
+*/
+
+// Set the number of estimated parameters.
+n = length(oo_.ols.ols_eq.beta);
+
+// We consider a kind of non informative prior by assuming that the inverse of the prior variance for β is zero.
+V0 = diag(Inf(n, 1));
+
+// We choose the prior mean for β randomly (around the OLS estimate).
+beta0 = oo_.ols.ols_eq.beta + randn(n, 1); 
+
+// Set prior for the variance of the error
+s2priormean = 17;
+s2df = 1;
+
+// Run bayesian estimation with normal-gamma prior. Because there is no closed
+// form expression for the joint posterior marginal distribution of β, a Gibbs
+// sampling algorithm is used (the prior for β and the inverse of σ² are independent).
+
+gibbslength = 1000000; // Set the number of iterations in Gibbs 
+burnin = 10000;        // Set the number of iterations to be discarded (try to remove the effects of the initial condition).
+steps = 10;            // Do not record all iterations (try to remove the dependence between the draws).
+
+ds = olsgibbs(ds, 'eqols', beta0, V0, s2priormean, s2df, gibbslength, burnin, steps, {'eqols', 'eqols_olsgibbs_fit'}, 'olsgibbs_eq',{'b2'; 'b3'});
+
+// Since we use a diffuse prior for β, the posterior mean of β should be close to the OLS estimate.
+if max(abs(oo_.ols.ols_eq.beta-oo_.olsgibbs.olsgibbs_eq.posterior.mean.beta))>.1
+   error('Something is wrong in the Gibbs sampling routine (univariate model)')
+end
+
+// We can plot the posterior distribution of the parameters:
+post = oo_.olsgibbs.olsgibbs_eq.posterior.density.b2;
+plot(post(:,1), post(:,2), '-k', 'linewidth', 2);
+axis tight
+box on
+hold on
+plot([oo_.olsgibbs.olsgibbs_eq.posterior.mean.beta(2), oo_.olsgibbs.olsgibbs_eq.posterior.mean.beta(2)], [0 max(post(:,2))], '-r')
+hold off
\ No newline at end of file
diff --git a/tests/estimation/univariate/data.csv b/tests/estimation/univariate/data.csv
new file mode 100644
index 0000000000000000000000000000000000000000..cf00089ead3fa44caf05d913e31f15ae81a14ce0
--- /dev/null
+++ b/tests/estimation/univariate/data.csv
@@ -0,0 +1,21 @@
+income,educ,jobexp,race
+5,2,9,1
+9.7,4,18,1
+28.4,8,21,1
+8.8,8,12,1
+21,8,14,1
+26.6,10,16,1
+25.4,12,16,1
+23.1,12,9,1
+22.5,12,18,1
+19.5,12,5,1
+21.7,12,7,0
+24.8,13,9,0
+30.1,14,12,0
+24.8,14,17,0
+28.5,15,19,0
+26,15,6,0
+38.9,16,17,0
+22.1,16,1,0
+33.1,17,10,0
+48.3,21,17,0
diff --git a/tests/estimation/univariate/ols/mc-ols.inc b/tests/estimation/univariate/ols/mc-ols.inc
new file mode 100644
index 0000000000000000000000000000000000000000..1c5baf209c4fa05e043a0d8d08674e36827f71d7
--- /dev/null
+++ b/tests/estimation/univariate/ols/mc-ols.inc
@@ -0,0 +1,104 @@
+verbatim;
+
+    options_.noprint = true;
+
+    number_of_simulations = 1;
+
+    calibrated_values = M_.params;
+    Sigma_e = M_.Sigma_e;
+
+    options_.bnlms.set_dynare_seed_to_default = false;
+
+    Beta = zeros(number_of_simulations, M_.param_nbr);
+
+    for i=1:number_of_simulations
+        % Set initial conditions randomly
+        firstobs = rand(3, length(M_.endo_names));
+        % Set parameters to calibrated values (because after the
+        % estimation parameters in equation 7 are updated with OLS
+        % estimator).
+        M_.params = calibrated_values;
+        M_.Sigma_e = Sigma_e;
+        % Simulate the model.
+        simdata = simul_backward_model(dseries(firstobs, dates('1995Q1'), M_.endo_names), 1100);
+        % Select a subsample.
+        simdata = simdata(simdata.dates(101:1100));
+        % Get vector of indices to exclude exogenous variables from the dataset.
+        names = regexp(simdata.name, 'res\w*');
+        idxs = find(cellfun(@isempty, names));
+        % Perform the estimation of equation 7.
+        if strcmp(M_.fname, 'ols_param_names')
+            dyn_ols(simdata{idxs}, {}, {'eq7'}, '', {{'de_g_yer_ecm_u2_stn_L1', 'de_g_yer_de_g_yer_L1'}});
+        elseif strcmp(M_.fname, 'ols_date_range')
+            dyn_ols(simdata{idxs}, {}, {'eq7'}, '', {}, simdata.dates(2:end-3));
+        else
+            dyn_ols(simdata{idxs}, {}, {'eq7'});
+        end
+        if i ~= number_of_simulations
+            oo_ = rmfield(oo_, 'ols');
+        end
+        % Store the estimation results in Beta
+        Beta(i, :) = M_.params';
+    end
+
+    % Get the indices of the estimated parameters
+    pid = oo_.ols.eq7.param_idxs;
+
+    if number_of_simulations > 1
+        if max(abs(calibrated_values(pid)-mean(Beta(:,pid)', 2)))>1e-2
+            error('There is probably an error in the OLS routine.')
+        end
+    else
+        if strcmp(M_.fname, 'ols')
+            good = [0.025487074270635
+                -0.126705792250240
+                0.002639663639062
+                0.486913131141265
+                -0.027702100375691];
+        elseif strcmp(M_.fname, 'ols_param_names')
+            good = [-0.125265361034515
+                0.497003481797959];
+        elseif strcmp(M_.fname, 'ols_date_range')
+            good = [0.468607715487806
+                -0.011224442004140
+                0.033681224841824
+                -0.126743281213504];
+        elseif strcmp(M_.fname, 'ols_wc_1')
+            good = [0.466534186307255
+                -0.010596174928406
+                0.035098464382347
+                -0.126502172176703];
+        elseif strcmp(M_.fname, 'ols_wc_2')
+            good = [0.485802603276717
+                0.002660854661647
+                0.025434782170432
+                -0.126939890810119
+                0.043688440124315];
+        elseif strcmp(M_.fname, 'ols_wc_3')
+            good = [0.490636551206316
+                0.014209413280418
+                0.028534044956486
+                -0.094387460262917];
+        end
+        if max(abs(good-Beta(:,pid)'))>1e-2
+            error('There is probably an error in the OLS routine.')
+        end
+        return
+    end
+
+    for i=1:length(pid)
+        figure(i)
+        hold on
+        title(strrep(M_.param_names(pid(i),:), '_', '\_'));
+        bandwidth = mh_optimal_bandwidth(Beta(:,pid(i)), length(Beta(:,pid(i))), -1, 'gaussian');
+        [abscissa, f] = kernel_density_estimate(Beta(:,pid(i)), 256, length(Beta(:,pid(i))), bandwidth, 'gaussian');
+        plot(abscissa, f, '-k', 'linewidth', 2);
+        line([calibrated_values(pid(i)) calibrated_values(pid(i))], [0 max(f)*1.05], 'LineWidth', 2, 'Color', 'r');
+        line([mean(Beta(:,pid(i))) mean(Beta(:,pid(i)))], [0 max(f)*1.05], 'LineWidth', 2, 'Color', 'g');
+        axis tight
+        box on
+        hold off
+    end
+
+end;
+
diff --git a/tests/estimation/univariate/ols/ols.mod b/tests/estimation/univariate/ols/ols.mod
new file mode 100644
index 0000000000000000000000000000000000000000..6cdf6a765283c53a1d84e77103bd563c012cd3d1
--- /dev/null
+++ b/tests/estimation/univariate/ols/ols.mod
@@ -0,0 +1,152 @@
+// --+ options: json=compute nopreprocessoroutput stochastic +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+f** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_g_yer_u2_stn_L1
+de_ehic_de_ehic_L1
+
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        =   de_ehic_de_ehic_L1       * DE_EHIC(-1)
+                 + res_DE_EHIC                                            ;
+
+
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+@#include "mc-ols.inc"
\ No newline at end of file
diff --git a/tests/estimation/univariate/ols/ols_date_range.mod b/tests/estimation/univariate/ols/ols_date_range.mod
new file mode 100644
index 0000000000000000000000000000000000000000..d0d8e1ea9351292bb3c1d0fc51cee77cd915b63f
--- /dev/null
+++ b/tests/estimation/univariate/ols/ols_date_range.mod
@@ -0,0 +1,149 @@
+// --+ options: json=compute nopreprocessoroutput stochastic +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+f** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_ehic_de_ehic_L1
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + (1-de_g_yer_de_q_yed_L1-de_g_yer_de_g_yer_L1)* diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        =   de_ehic_de_ehic_L1       * DE_EHIC(-1)
+                 + res_DE_EHIC                                            ;
+
+//
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+@#include "mc-ols.inc"
\ No newline at end of file
diff --git a/tests/estimation/univariate/ols/ols_param_names.mod b/tests/estimation/univariate/ols/ols_param_names.mod
new file mode 100644
index 0000000000000000000000000000000000000000..97ea058a72ca669e9b2d6b0ea7dd5e7a212899d1
--- /dev/null
+++ b/tests/estimation/univariate/ols/ols_param_names.mod
@@ -0,0 +1,152 @@
+// --+ options: json=compute nopreprocessoroutput stochastic +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+f** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_g_yer_u2_stn_L1
+de_ehic_de_ehic_L1
+
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        =   de_ehic_de_ehic_L1       * DE_EHIC(-1)
+                 + res_DE_EHIC                                            ;
+
+
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+@#include "mc-ols.inc"
diff --git a/tests/estimation/univariate/ols/ols_wc_1.mod b/tests/estimation/univariate/ols/ols_wc_1.mod
new file mode 100644
index 0000000000000000000000000000000000000000..d0d8e1ea9351292bb3c1d0fc51cee77cd915b63f
--- /dev/null
+++ b/tests/estimation/univariate/ols/ols_wc_1.mod
@@ -0,0 +1,149 @@
+// --+ options: json=compute nopreprocessoroutput stochastic +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+f** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_ehic_de_ehic_L1
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + (1-de_g_yer_de_q_yed_L1-de_g_yer_de_g_yer_L1)* diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        =   de_ehic_de_ehic_L1       * DE_EHIC(-1)
+                 + res_DE_EHIC                                            ;
+
+//
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+@#include "mc-ols.inc"
\ No newline at end of file
diff --git a/tests/estimation/univariate/ols/ols_wc_2.mod b/tests/estimation/univariate/ols/ols_wc_2.mod
new file mode 100644
index 0000000000000000000000000000000000000000..7f370f9b2bcbc0b297252ad91070788adae92ffa
--- /dev/null
+++ b/tests/estimation/univariate/ols/ols_wc_2.mod
@@ -0,0 +1,152 @@
+// --+ options: json=compute nopreprocessoroutput stochastic +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+f** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_ehic_de_ehic_L1
+p
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+p = 0;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 + de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + (p-de_g_yer_de_q_yed_L1) * diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        =   de_ehic_de_ehic_L1       * DE_EHIC(-1)
+                 + res_DE_EHIC                                            ;
+
+//
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+@#include "mc-ols.inc"
\ No newline at end of file
diff --git a/tests/estimation/univariate/ols/ols_wc_3.mod b/tests/estimation/univariate/ols/ols_wc_3.mod
new file mode 100644
index 0000000000000000000000000000000000000000..780cec88f612d944f6db8c3e7c7f0e74350e6c37
--- /dev/null
+++ b/tests/estimation/univariate/ols/ols_wc_3.mod
@@ -0,0 +1,149 @@
+// --+ options: json=compute nopreprocessoroutput stochastic +--
+
+/* REMARK
+** ------
+**
+** You need to have the first line on top of the mod file. The options defined on this line are passed
+f** to the dynare command (you can add other options, separated by spaces or commas). The option defined
+** here is mandatory for the decomposition. It forces Dynare to output another representation of the
+** model in JSON file (additionaly to the matlab files) which is used here to manipulate the equations.
+*/
+
+var
+U2_Q_YED
+U2_G_YER
+U2_STN
+U2_ESTN
+U2_EHIC
+DE_Q_YED
+DE_G_YER
+DE_EHIC
+
+;
+
+varexo
+res_U2_Q_YED
+res_U2_G_YER
+res_U2_STN
+res_U2_ESTN
+res_U2_EHIC
+res_DE_Q_YED
+res_DE_G_YER
+res_DE_EHIC
+;
+
+parameters
+u2_q_yed_ecm_u2_q_yed_L1
+u2_q_yed_ecm_u2_stn_L1
+u2_q_yed_u2_g_yer_L1
+u2_q_yed_u2_stn_L1
+u2_g_yer_ecm_u2_q_yed_L1
+u2_g_yer_ecm_u2_stn_L1
+u2_g_yer_u2_q_yed_L1
+u2_g_yer_u2_g_yer_L1
+u2_g_yer_u2_stn_L1
+u2_stn_ecm_u2_q_yed_L1
+u2_stn_ecm_u2_stn_L1
+u2_stn_u2_q_yed_L1
+u2_stn_u2_g_yer_L1
+u2_estn_u2_estn_L1
+u2_ehic_u2_ehic_L1
+
+de_q_yed_ecm_de_q_yed_L1
+de_q_yed_ecm_u2_stn_L1
+de_q_yed_de_g_yer_L1
+de_q_yed_u2_stn_L1
+de_g_yer_ecm_de_q_yed_L1
+de_g_yer_ecm_u2_stn_L1
+de_g_yer_de_q_yed_L1
+de_g_yer_de_g_yer_L1
+de_ehic_de_ehic_L1
+
+;
+
+u2_q_yed_ecm_u2_q_yed_L1  = -0.82237516589315   ;
+u2_q_yed_ecm_u2_stn_L1    = -0.323715338568976  ;
+u2_q_yed_u2_g_yer_L1      =  0.0401361895021084 ;
+u2_q_yed_u2_stn_L1        =  0.058397703958446  ;
+u2_g_yer_ecm_u2_q_yed_L1  =  0.0189896046977421 ;
+u2_g_yer_ecm_u2_stn_L1    = -0.109597659887432  ;
+u2_g_yer_u2_q_yed_L1      =  0.0037667967632025 ;
+u2_g_yer_u2_g_yer_L1      =  0.480506381923644  ;
+u2_g_yer_u2_stn_L1        = -0.0722359286123494 ;
+u2_stn_ecm_u2_q_yed_L1    = -0.0438500662608356 ;
+u2_stn_ecm_u2_stn_L1      = -0.153283917138772  ;
+u2_stn_u2_q_yed_L1        =  0.0328744983772825 ;
+u2_stn_u2_g_yer_L1        =  0.292121949736756  ;
+u2_estn_u2_estn_L1        =  1                  ;
+u2_ehic_u2_ehic_L1        =  1                  ;
+
+de_q_yed_ecm_de_q_yed_L1  = -0.822375165893149  ;
+de_q_yed_ecm_u2_stn_L1    = -0.323715338568977  ;
+de_q_yed_de_g_yer_L1      =  0.0401361895021082 ;
+de_q_yed_u2_stn_L1        =  0.0583977039584461 ;
+de_g_yer_ecm_de_q_yed_L1  =  0.0189896046977422 ;
+de_g_yer_ecm_u2_stn_L1    = -0.109597659887433  ;
+de_g_yer_de_q_yed_L1      =  0.00376679676320256;
+de_g_yer_de_g_yer_L1      =  0.480506381923643  ;
+de_ehic_de_ehic_L1        =  1                  ;
+
+
+model(linear);
+[name = 'eq1']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+[name = 'eq2']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+[name = 'eq3']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+[name = 'eq4']
+U2_ESTN        =   u2_estn_u2_estn_L1       * U2_ESTN(-1)
+                 + res_U2_ESTN                                            ;
+[name = 'eq5']
+U2_EHIC        =   u2_ehic_u2_ehic_L1       * U2_EHIC(-1)
+                 + res_U2_EHIC                                            ;
+[name = 'eq6']
+diff(DE_Q_YED) =   de_q_yed_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 + de_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_q_yed_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 + de_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_DE_Q_YED                                           ;
+[name = 'eq7']
+diff(DE_G_YER) =   de_g_yer_ecm_de_q_yed_L1 * (DE_Q_YED(-1) - DE_EHIC(-1))
+                 - de_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + de_g_yer_de_q_yed_L1     * diff(DE_Q_YED(-1))
+                 - de_g_yer_de_g_yer_L1     * diff(DE_G_YER(-1))
+                 - (1-de_g_yer_de_q_yed_L1-de_g_yer_de_g_yer_L1)* diff(U2_STN(-1))
+                 + res_DE_G_YER                                           ;
+[name = 'eq8']
+DE_EHIC        =   de_ehic_de_ehic_L1       * DE_EHIC(-1)
+                 + res_DE_EHIC                                            ;
+
+//
+
+end;
+
+shocks;
+var res_U2_Q_YED = 0.005;
+var res_U2_G_YER = 0.005;
+var res_U2_STN = 0.005;
+var res_U2_ESTN = 0.005;
+var res_U2_EHIC = 0.005;
+var res_DE_Q_YED = 0.005;
+var res_DE_G_YER = 0.005;
+var res_DE_EHIC = 0.005;
+end;
+
+@#include "mc-ols.inc"
\ No newline at end of file
diff --git a/tests/exogenous-observed-variables/preprocessor.mod b/tests/exogenous-observed-variables/preprocessor.mod
new file mode 100644
index 0000000000000000000000000000000000000000..20a71f2b34e47579a2d23d3ded90cf6a1f325be9
--- /dev/null
+++ b/tests/exogenous-observed-variables/preprocessor.mod
@@ -0,0 +1,32 @@
+var y z;
+
+varexo e x u;
+
+parameters rho;
+
+rho = .9;
+
+
+model(linear);
+y = z +  e ;
+z = rho*z(-1) + u;
+end;
+
+shocks;
+var e; stderr .01;
+var u; stderr .01;
+end;
+
+varobs y;
+
+varexobs x;
+
+assert(length(options_.varobs)==1);
+assert(length(options_.varexobs)==1);
+assert(length(options_.varobs_id)==1);
+assert(length(options_.varexobs_id)==1);
+assert(options_.varobs_id==1);
+assert(options_.varexobs_id==2);
+assert(options_.varobs{1}=='y');
+assert(options_.varexobs{1}=='x');
+
diff --git a/tests/matrix_notation/benchmark.mod b/tests/matrix_notation/benchmark.mod
new file mode 100644
index 0000000000000000000000000000000000000000..c33ae1358ffa1d51f63fbbee12077a2fab7decc8
--- /dev/null
+++ b/tests/matrix_notation/benchmark.mod
@@ -0,0 +1,44 @@
+/* This file is used as a benchmark against with the other tests with external
+   functions are compared.
+   It is almost the same as example1.mod, except that the shocks process is
+   nonlinear (in order to have a non-zero Hessian of the
+   external function) */
+
+var y, c, k, h, a, b;
+varexo e, u;
+parameters beta, alpha, delta, theta, psi, rho, tau;
+
+alpha = 0.36;
+rho   = 0.95;
+tau   = 0.025;
+beta  = 0.99;
+delta = 0.025;
+psi   = 0;
+theta = 2.95;
+
+phi   = 0.1;
+
+model;
+c*theta*h^(1+psi)=(1-alpha)*y;
+k = beta*(((exp(b)*c)/(exp(b(+1))*c(+1)))
+          *(exp(b(+1))*alpha*y(+1)+(1-delta)*k));
+y = exp(a)*(k(-1)^alpha)*(h^(1-alpha));
+k = exp(b)*(y-c)+(1-delta)*k(-1) ;
+a = rho*a(-1)^2+5*tau*b(-1)^2 + e;
+b = 3*tau/2*a(-1)^2+7*rho/3*b(-1)^2 + u;
+end;
+
+initval;
+y = 1.08068253095672;
+c = 0.80359242014163;
+h = 0.29175631001732;
+k = 11.08360443260358;
+end;
+
+shocks;
+var e; stderr 0.009;
+var u; stderr 0.009;
+var e, u = phi*0.009*0.009;
+end;
+
+stoch_simul;
diff --git a/tests/matrix_notation/deterministic_matrix.mod b/tests/matrix_notation/deterministic_matrix.mod
new file mode 100644
index 0000000000000000000000000000000000000000..ff72d56c030f3ca8edff99e9bd1f88ac129d9658
--- /dev/null
+++ b/tests/matrix_notation/deterministic_matrix.mod
@@ -0,0 +1,38 @@
+// Do not forget to update deterministic_scalar.mod when this file is modified
+
+var(rows=3) X, Y, Z;
+var t;
+varexo(rows=3) E, U, V;
+parameters(rows=3, cols=3) P;
+
+P = [.1, .2, -.3; -.1, .5, .1; .2, -.3, .9];
+
+model;
+  X = P*X(-1)+E;
+  transpose(Y) = transpose(Y(-1))*transpose(P)+transpose(U);
+  Z = V;
+  t = Y[1](-1) + Y[2](+1);
+end;
+
+shocks;
+  var E;
+  periods 1 2;
+  values [0.5; 0.6; 0.7] [0.2; 0.3; 0.4];
+
+  var U[1];
+  periods 3;
+  values 0.8;
+
+  var U[2];
+  periods 3;
+  values 0.7;
+
+  var V[:];
+  periods 1;
+  values 0.1;
+end;
+
+perfect_foresight_setup(periods=50);
+perfect_foresight_solver;
+
+write_latex_dynamic_model;
diff --git a/tests/matrix_notation/deterministic_scalar.mod b/tests/matrix_notation/deterministic_scalar.mod
new file mode 100644
index 0000000000000000000000000000000000000000..3a893acc49c066e99fe029d63705d4481cf0b1f3
--- /dev/null
+++ b/tests/matrix_notation/deterministic_scalar.mod
@@ -0,0 +1,70 @@
+// Scalar translation of deterministic_matrix.mod
+// The declaration orders are the same as those of the expanded matrix version
+var t X_1 X_2 X_3 Y_1 Y_2 Y_3 Z_1 Z_2 Z_3;
+varexo E_1 E_2 E_3 U_1 U_2 U_3 V_1 V_2 V_3;
+parameters P_1_1 P_1_2 P_1_3 P_2_1 P_2_2 P_2_3 P_3_1 P_3_2 P_3_3;
+
+P_1_1 = .1;
+P_1_2 = .2;
+P_1_3 = -.3;
+P_2_1 = -.1;
+P_2_2 = .5;
+P_2_3 = .1;
+P_3_1 = .2;
+P_3_2 = -.3;
+P_3_3 = .9;
+
+model;
+  X_1 = P_1_1*X_1(-1) + P_1_2*X_2(-1) + P_1_3*X_3(-1) + E_1;
+  X_2 = P_2_1*X_1(-1) + P_2_2*X_2(-1) + P_2_3*X_3(-1) + E_2;
+  X_3 = P_3_1*X_1(-1) + P_3_2*X_2(-1) + P_3_3*X_3(-1) + E_3;
+  Y_1 = P_1_1*Y_1(-1) + P_1_2*Y_2(-1) + P_1_3*Y_3(-1) + U_1;
+  Y_2 = P_2_1*Y_1(-1) + P_2_2*Y_2(-1) + P_2_3*Y_3(-1) + U_2;
+  Y_3 = P_3_1*Y_1(-1) + P_3_2*Y_2(-1) + P_3_3*Y_3(-1) + U_3;
+  Z_1 = V_1;
+  Z_2 = V_2;
+  Z_3 = V_3;
+  t = Y_1(-1) + Y_2(+1);
+end;
+
+shocks;
+  var E_1;
+  periods 1 2;
+  values 0.5 0.2;
+
+  var E_2;
+  periods 1 2;
+  values 0.6 0.3;
+
+  var E_3;
+  periods 1 2;
+  values 0.7 0.4;
+
+  var U_1;
+  periods 3;
+  values 0.8;
+
+  var U_2;
+  periods 3;
+  values 0.7;
+
+  var V_1;
+  periods 1;
+  values 0.1;
+
+  var V_2;
+  periods 1;
+  values 0.1;
+
+  var V_3;
+  periods 1;
+  values 0.1;
+end;
+
+perfect_foresight_setup(periods=50);
+perfect_foresight_solver;
+
+L = load('deterministic_matrix_results.mat');
+if max(max(abs(L.oo_.endo_simul - oo_.endo_simul))) > 1e-12
+  error('Failure in matrix expansion')
+end
diff --git a/tests/matrix_notation/extFunFirstDerivMatrix.m b/tests/matrix_notation/extFunFirstDerivMatrix.m
new file mode 100644
index 0000000000000000000000000000000000000000..68c27d3a883cc179615b364d8bcee17405ba7b04
--- /dev/null
+++ b/tests/matrix_notation/extFunFirstDerivMatrix.m
@@ -0,0 +1,4 @@
+function dy=extFunFirstDerivMatrix(a,b,c)
+dy = [ c(1)^2 0        5*c(2)^2 0        2*a(1)*c(1) 10*b(1)*c(2);
+       0      3*c(1)^2 0        7*c(2)^2 6*a(2)*c(1) 14*b(2)*c(2) ];
+end
diff --git a/tests/matrix_notation/extFunNoDerivsMatrix.m b/tests/matrix_notation/extFunNoDerivsMatrix.m
new file mode 100644
index 0000000000000000000000000000000000000000..e7541cee70badbb3424555eee5c1a45608049e1b
--- /dev/null
+++ b/tests/matrix_notation/extFunNoDerivsMatrix.m
@@ -0,0 +1,3 @@
+function y=extFunNoDerivsMatrix(a,b,c)
+y=[a(1), 5*b(1); 3*a(2) 7*b(2)]*c.^2;
+end
diff --git a/tests/matrix_notation/extFunWithFirstAndSecondDerivsMatrix.m b/tests/matrix_notation/extFunWithFirstAndSecondDerivsMatrix.m
new file mode 100644
index 0000000000000000000000000000000000000000..e7b227909c2ef3dfa7461db60fff6e0e3295c6f8
--- /dev/null
+++ b/tests/matrix_notation/extFunWithFirstAndSecondDerivsMatrix.m
@@ -0,0 +1,20 @@
+function [y dy d2y]=extFunWithFirstAndSecondDerivsMatrix(a,b,c)
+y=[a(1), 5*b(1); 3*a(2), 7*b(2)]*c.^2;
+
+dy = [ c(1)^2 0        5*c(2)^2 0        2*a(1)*c(1) 10*b(1)*c(2);
+       0      3*c(1)^2 0        7*c(2)^2 6*a(2)*c(1) 14*b(2)*c(2) ];
+
+d2y=zeros(2,6,6);
+d2y(1,1,5) = 2*c(1);
+d2y(1,3,6) = 10*c(2);
+d2y(1,5,1) = 2*c(1);
+d2y(1,5,5) = 2*a(1);
+d2y(1,6,3) = 10*c(2);
+d2y(1,6,6) = 10*b(1);
+d2y(2,2,5) = 6*c(1);
+d2y(2,4,6) = 14*c(2);
+d2y(2,5,2) = 6*c(1);
+d2y(2,5,5) = 6*a(2);
+d2y(2,6,4) = 14*c(2);
+d2y(2,6,6) = 14*b(2);
+end
diff --git a/tests/matrix_notation/first_and_2nd_deriv_given_matrix.mod b/tests/matrix_notation/first_and_2nd_deriv_given_matrix.mod
new file mode 100644
index 0000000000000000000000000000000000000000..120ef1043a2c0ec03f482f72ab022816acb092bb
--- /dev/null
+++ b/tests/matrix_notation/first_and_2nd_deriv_given_matrix.mod
@@ -0,0 +1,71 @@
+var y, c, k, h;
+var(rows = 2) A; // A == [a; b]
+varexo(rows = 2) E; // E == [e; u]
+parameters beta, alpha, delta, theta, psi;
+parameters(rows=2,cols=2) P;
+
+alpha = 0.36;
+rho   = 0.95;
+tau   = 0.025;
+beta  = 0.99;
+delta = 0.025;
+psi   = 0;
+theta = 2.95;
+
+phi   = 0.1;
+
+P = [rho, tau; tau/2, rho/3];
+
+external_function(nargs=3, name=extFunWithFirstAndSecondDerivsMatrix, in_arg_dim=[2,2,2],
+                  out_arg_dim=2, first_deriv_provided, second_deriv_provided);
+
+model;
+[endogenous='c',name='law of motion of capital']
+c*theta*h^(1+psi)=(1-alpha)*y;
+k = beta*(((exp(A[2])*c)/(exp(A[2](+1))*c(+1)))
+          *(exp(A[2](+1))*alpha*y(+1)+(1-delta)*k));
+y = exp(A[1])*(k(-1)^alpha)*(h^(1-alpha));
+k = exp(A[2])*(y-c)+(1-delta)*k(-1) ;
+A = extFunWithFirstAndSecondDerivsMatrix(P[:,1], transpose(P[:,2]), A(-1)) + E;
+end;
+
+initval;
+y = 1.08068253095672;
+c = 0.80359242014163;
+h = 0.29175631001732;
+k = 11.08360443260358;
+
+A[1] = 0;
+A[2] = 0;
+E[:] = 0;
+end;
+
+shocks;
+var E[:]; stderr 0.009;
+var E[1], E[2] = phi*0.009*0.009;
+end;
+
+stoch_simul;
+
+L = load('benchmark_results.mat');
+if max(max(abs(L.oo_.dr.ghu - oo_.dr.ghu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghx - oo_.dr.ghx))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghxu - oo_.dr.ghxu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghxx - oo_.dr.ghxx))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghuu - oo_.dr.ghuu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghs2 - oo_.dr.ghs2))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.var - oo_.var))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
diff --git a/tests/matrix_notation/first_and_2nd_deriv_given_matrix_dll.mod b/tests/matrix_notation/first_and_2nd_deriv_given_matrix_dll.mod
new file mode 100644
index 0000000000000000000000000000000000000000..570cf021dedddde43c01f11f0d8e5e3761a79f98
--- /dev/null
+++ b/tests/matrix_notation/first_and_2nd_deriv_given_matrix_dll.mod
@@ -0,0 +1,71 @@
+var y, c, k, h;
+var(rows = 2) A; // A == [a; b]
+varexo(rows = 2) E; // E == [e; u]
+parameters beta, alpha, delta, theta, psi;
+parameters(rows=2,cols=2) P;
+
+alpha = 0.36;
+rho   = 0.95;
+tau   = 0.025;
+beta  = 0.99;
+delta = 0.025;
+psi   = 0;
+theta = 2.95;
+
+phi   = 0.1;
+
+P = [rho, tau; tau/2, rho/3];
+
+external_function(nargs=3, name=extFunWithFirstAndSecondDerivsMatrix, in_arg_dim=[2,2,2],
+                  out_arg_dim=2, first_deriv_provided, second_deriv_provided);
+
+model(use_dll);
+[endogenous='c',name='law of motion of capital']
+c*theta*h^(1+psi)=(1-alpha)*y;
+k = beta*(((exp(A[2])*c)/(exp(A[2](+1))*c(+1)))
+          *(exp(A[2](+1))*alpha*y(+1)+(1-delta)*k));
+y = exp(A[1])*(k(-1)^alpha)*(h^(1-alpha));
+k = exp(A[2])*(y-c)+(1-delta)*k(-1) ;
+A = extFunWithFirstAndSecondDerivsMatrix(P[:,1], transpose(P[:,2]), A(-1)) + E;
+end;
+
+initval;
+y = 1.08068253095672;
+c = 0.80359242014163;
+h = 0.29175631001732;
+k = 11.08360443260358;
+
+A[1] = 0;
+A[2] = 0;
+E[:] = 0;
+end;
+
+shocks;
+var E[:]; stderr 0.009;
+var E[1], E[2] = phi*0.009*0.009;
+end;
+
+stoch_simul;
+
+L = load('benchmark_results.mat');
+if max(max(abs(L.oo_.dr.ghu - oo_.dr.ghu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghx - oo_.dr.ghx))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghxu - oo_.dr.ghxu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghxx - oo_.dr.ghxx))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghuu - oo_.dr.ghuu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghs2 - oo_.dr.ghs2))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.var - oo_.var))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
diff --git a/tests/matrix_notation/first_deriv_given_matrix.mod b/tests/matrix_notation/first_deriv_given_matrix.mod
new file mode 100644
index 0000000000000000000000000000000000000000..431df3d64395ef2c97e1a4a6209a8c401eb7c136
--- /dev/null
+++ b/tests/matrix_notation/first_deriv_given_matrix.mod
@@ -0,0 +1,72 @@
+// --+ options: json=compute +--
+
+var y, c, k, h;
+var(rows = 2) A; // A == [a; b]
+varexo(rows = 2) E; // E == [e; u]
+parameters beta, alpha, delta, theta, psi;
+parameters(rows=2,cols=2) P;
+
+alpha = 0.36;
+rho   = 0.95;
+tau   = 0.025;
+beta  = 0.99;
+delta = 0.025;
+psi   = 0;
+theta = 2.95;
+
+phi   = 0.1;
+
+P = [rho, tau; tau/2, rho/3];
+
+external_function(nargs=3, name=extFunNoDerivsMatrix, in_arg_dim=[2,2,2],
+                  out_arg_dim=2, first_deriv_provided=extFunFirstDerivMatrix);
+
+model;
+c*theta*h^(1+psi)=(1-alpha)*y;
+k = beta*(((exp(A[2])*c)/(exp(A[2](+1))*c(+1)))
+          *(exp(A[2](+1))*alpha*y(+1)+(1-delta)*k));
+y = exp(A[1])*(k(-1)^alpha)*(h^(1-alpha));
+k = exp(A[2])*(y-c)+(1-delta)*k(-1) ;
+A = extFunNoDerivsMatrix(P[:,1], transpose(P[:,2]), A(-1)) + E;
+end;
+
+initval;
+y = 1.08068253095672;
+c = 0.80359242014163;
+h = 0.29175631001732;
+k = 11.08360443260358;
+
+A[1] = 0;
+A[2] = 0;
+E[:] = 0;
+end;
+
+shocks;
+var E[:]; stderr 0.009;
+var E[1], E[2] = phi*0.009*0.009;
+end;
+
+stoch_simul;
+
+L = load('benchmark_results.mat');
+if max(max(abs(L.oo_.dr.ghu - oo_.dr.ghu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghx - oo_.dr.ghx))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghxu - oo_.dr.ghxu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghxx - oo_.dr.ghxx))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghuu - oo_.dr.ghuu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghs2 - oo_.dr.ghs2))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.var - oo_.var))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
diff --git a/tests/matrix_notation/first_deriv_given_matrix_dll.mod b/tests/matrix_notation/first_deriv_given_matrix_dll.mod
new file mode 100644
index 0000000000000000000000000000000000000000..070195c210c4d1c4db8a3b3a6de874f4189050e9
--- /dev/null
+++ b/tests/matrix_notation/first_deriv_given_matrix_dll.mod
@@ -0,0 +1,73 @@
+// --+ options: json=compute +--
+
+var y, c, k, h;
+var(rows = 2) A; // A == [a; b]
+varexo(rows = 2) E; // E == [e; u]
+parameters beta, alpha, delta, theta, psi;
+parameters(rows=2,cols=2) P;
+
+alpha = 0.36;
+rho   = 0.95;
+tau   = 0.025;
+beta  = 0.99;
+delta = 0.025;
+psi   = 0;
+theta = 2.95;
+
+phi   = 0.1;
+
+P = [rho, tau; tau/2, rho/3];
+
+external_function(nargs=3, name=extFunNoDerivsMatrix, in_arg_dim=[2,2,2],
+                  out_arg_dim=2, first_deriv_provided=extFunFirstDerivMatrix);
+
+model(use_dll);
+c*theta*h^(1+psi)=(1-alpha)*y;
+k = beta*(((exp(A[2])*c)/(exp(A[2](+1))*c(+1)))
+          *(exp(A[2](+1))*alpha*y(+1)+(1-delta)*k));
+y = exp(A[1])*(k(-1)^alpha)*(h^(1-alpha));
+k = exp(A[2])*(y-c)+(1-delta)*k(-1) ;
+A = extFunNoDerivsMatrix(P[:,1], transpose(P[:,2]), A(-1)) + E;
+end;
+
+initval;
+y = 1.08068253095672;
+c = 0.80359242014163;
+h = 0.29175631001732;
+k = 11.08360443260358;
+
+A[1] = 0;
+A[2] = 0;
+E[:] = 0;
+
+end;
+
+shocks;
+var E[:]; stderr 0.009;
+var E[1], E[2] = phi*0.009*0.009;
+end;
+
+stoch_simul;
+
+L = load('benchmark_results.mat');
+if max(max(abs(L.oo_.dr.ghu - oo_.dr.ghu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghx - oo_.dr.ghx))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghxu - oo_.dr.ghxu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghxx - oo_.dr.ghxx))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghuu - oo_.dr.ghuu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghs2 - oo_.dr.ghs2))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.var - oo_.var))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
diff --git a/tests/matrix_notation/no_deriv_given_matrix.mod b/tests/matrix_notation/no_deriv_given_matrix.mod
new file mode 100644
index 0000000000000000000000000000000000000000..08c22198ffa5c313da9c1f24db60884ad4ee2ed0
--- /dev/null
+++ b/tests/matrix_notation/no_deriv_given_matrix.mod
@@ -0,0 +1,71 @@
+// --+ options: json=compute +--
+
+var y, c, k, h;
+var(rows = 2) A; // A == [a; b]
+varexo(rows = 2) E; // E == [e; u]
+parameters beta, alpha, delta, theta, psi;
+parameters(rows=2,cols=2) P;
+
+alpha = 0.36;
+rho   = 0.95;
+tau   = 0.025;
+beta  = 0.99;
+delta = 0.025;
+psi   = 0;
+theta = 2.95;
+
+phi   = 0.1;
+
+P = [rho, tau; tau/2, rho/3];
+
+external_function(nargs=3, name=extFunNoDerivsMatrix, in_arg_dim=[2,2,2], out_arg_dim=2);
+
+model;
+c*theta*h^(1+psi)=(1-alpha)*y;
+k = beta*(((exp(A[2])*c)/(exp(A[2](+1))*c(+1)))
+          *(exp(A[2](+1))*alpha*y(+1)+(1-delta)*k));
+y = exp(A[1])*(k(-1)^alpha)*(h^(1-alpha));
+k = exp(A[2])*(y-c)+(1-delta)*k(-1) ;
+A = extFunNoDerivsMatrix(P[:,1], transpose(P[:,2]), A(-1)) + E;
+end;
+
+initval;
+y = 1.08068253095672;
+c = 0.80359242014163;
+h = 0.29175631001732;
+k = 11.08360443260358;
+
+A[1] = 0;
+A[2] = 0;
+E[:] = 0;
+end;
+
+shocks;
+var E[:]; stderr 0.009;
+var E[1], E[2] = phi*0.009*0.009;
+end;
+
+stoch_simul;
+
+L = load('benchmark_results.mat');
+if max(max(abs(L.oo_.dr.ghu - oo_.dr.ghu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghx - oo_.dr.ghx))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghxu - oo_.dr.ghxu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghxx - oo_.dr.ghxx))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghuu - oo_.dr.ghuu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghs2 - oo_.dr.ghs2))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.var - oo_.var))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
diff --git a/tests/matrix_notation/no_deriv_given_matrix_dll.mod b/tests/matrix_notation/no_deriv_given_matrix_dll.mod
new file mode 100644
index 0000000000000000000000000000000000000000..ccbedff1c778bf66748e7e9c5ec1074ea190fab3
--- /dev/null
+++ b/tests/matrix_notation/no_deriv_given_matrix_dll.mod
@@ -0,0 +1,71 @@
+// --+ options: json=compute +--
+
+var y, c, k, h;
+var(rows = 2) A; // A == [a; b]
+varexo(rows = 2) E; // E == [e; u]
+parameters beta, alpha, delta, theta, psi;
+parameters(rows=2,cols=2) P;
+
+alpha = 0.36;
+rho   = 0.95;
+tau   = 0.025;
+beta  = 0.99;
+delta = 0.025;
+psi   = 0;
+theta = 2.95;
+
+phi   = 0.1;
+
+P = [rho, tau; tau/2, rho/3];
+
+external_function(nargs=3, name=extFunNoDerivsMatrix, in_arg_dim=[2,2,2], out_arg_dim=2);
+
+model(use_dll);
+c*theta*h^(1+psi)=(1-alpha)*y;
+k = beta*(((exp(A[2])*c)/(exp(A[2](+1))*c(+1)))
+          *(exp(A[2](+1))*alpha*y(+1)+(1-delta)*k));
+y = exp(A[1])*(k(-1)^alpha)*(h^(1-alpha));
+k = exp(A[2])*(y-c)+(1-delta)*k(-1) ;
+A = extFunNoDerivsMatrix(P[:,1], transpose(P[:,2]), A(-1)) + E;
+end;
+
+initval;
+y = 1.08068253095672;
+c = 0.80359242014163;
+h = 0.29175631001732;
+k = 11.08360443260358;
+
+A[1] = 0;
+A[2] = 0;
+E[:] = 0;
+end;
+
+shocks;
+var E[:]; stderr 0.009;
+var E[1], E[2] = phi*0.009*0.009;
+end;
+
+stoch_simul;
+
+L = load('benchmark_results.mat');
+if max(max(abs(L.oo_.dr.ghu - oo_.dr.ghu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghx - oo_.dr.ghx))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghxu - oo_.dr.ghxu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghxx - oo_.dr.ghxx))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghuu - oo_.dr.ghuu))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.dr.ghs2 - oo_.dr.ghs2))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
+if max(max(abs(L.oo_.var - oo_.var))) > 1e-12
+  error('Failure in matrix notation with external function')
+end
diff --git a/tests/matrix_notation/stochastic_matrix.mod b/tests/matrix_notation/stochastic_matrix.mod
new file mode 100644
index 0000000000000000000000000000000000000000..d055f5e60c4c5ee028b968792e63c76889589c61
--- /dev/null
+++ b/tests/matrix_notation/stochastic_matrix.mod
@@ -0,0 +1,46 @@
+// Do not forget to update stochastic_scalar.mod when this file is modified
+
+var(rows=3) X, Y, Z, T;
+var r;
+varexo(rows=3) E, U, V, W;
+varexo f;
+parameters(rows=3, cols=3) P;
+varexo_det(rows=3) D;
+
+P = [.1, .2, -.3; -.1, .5, .1; .2, -.3, .9];
+
+model;
+  X = P*X(-1)+E;
+  transpose(Y) = transpose(Y(-1))*transpose(P)+transpose(U);
+  Z[1] = V[1];
+  Z[2] = V[2];
+  Z[3] = V[3];
+  T = D + W;
+  r = 0.9*r(+1)+f;
+end;
+
+shocks;
+  var E = [ 0.1, 0.2, 0.3 ];
+  var E[1], E[2] = 0.08;
+
+  var U[1] = 0.4;
+  var U[2]; stderr 0.5;
+  var U[3]; stderr 0.6;
+  corr U[1], U[2] = 0.09;
+
+  var V; stderr [ 1.1, 1.2, 1.3 ];
+
+  vcov W = [
+      1, 0.2, 0.3;
+    0.2, 5,   0.6;
+    0.3, 0.6,   9
+  ];
+
+  var f = 3;
+  var f, E[2] = 0.5;
+  corr U[1], f = 0.7;
+end;
+
+stoch_simul(order=1, nodecomposition, irf=0);
+
+write_latex_dynamic_model;
diff --git a/tests/matrix_notation/stochastic_scalar.mod b/tests/matrix_notation/stochastic_scalar.mod
new file mode 100644
index 0000000000000000000000000000000000000000..3c5be1857c21938e5398bffb8f341eba5241d8bf
--- /dev/null
+++ b/tests/matrix_notation/stochastic_scalar.mod
@@ -0,0 +1,72 @@
+// Scalar translation of stochastic_matrix.mod
+// The declaration orders are the same as those of the expanded matrix version
+var r X_1 X_2 X_3 Y_1 Y_2 Y_3 Z_1 Z_2 Z_3 T_1 T_2 T_3;
+varexo f E_1 E_2 E_3 U_1 U_2 U_3 V_1 V_2 V_3 W_1 W_2 W_3;
+parameters P_1_1 P_1_2 P_1_3 P_2_1 P_2_2 P_2_3 P_3_1 P_3_2 P_3_3;
+varexo_det D_1 D_2 D_3;
+
+P_1_1 = .1;
+P_1_2 = .2;
+P_1_3 = -.3;
+P_2_1 = -.1;
+P_2_2 = .5;
+P_2_3 = .1;
+P_3_1 = .2;
+P_3_2 = -.3;
+P_3_3 = .9;
+
+model;
+  X_1 = P_1_1*X_1(-1) + P_1_2*X_2(-1) + P_1_3*X_3(-1) + E_1;
+  X_2 = P_2_1*X_1(-1) + P_2_2*X_2(-1) + P_2_3*X_3(-1) + E_2;
+  X_3 = P_3_1*X_1(-1) + P_3_2*X_2(-1) + P_3_3*X_3(-1) + E_3;
+  Y_1 = P_1_1*Y_1(-1) + P_1_2*Y_2(-1) + P_1_3*Y_3(-1) + U_1;
+  Y_2 = P_2_1*Y_1(-1) + P_2_2*Y_2(-1) + P_2_3*Y_3(-1) + U_2;
+  Y_3 = P_3_1*Y_1(-1) + P_3_2*Y_2(-1) + P_3_3*Y_3(-1) + U_3;
+  Z_1 = V_1;
+  Z_2 = V_2;
+  Z_3 = V_3;
+  T_1 = D_1 + W_1;
+  T_2 = D_2 + W_2;
+  T_3 = D_3 + W_3;
+  r = 0.9*r(+1)+f;
+end;
+
+shocks;
+  var E_1 = 0.1;
+  var E_2 = 0.2;
+  var E_3 = 0.3;
+  var E_1, E_2 = 0.08;
+
+  var U_1 = 0.4;
+  var U_2; stderr 0.5;
+  var U_3; stderr 0.6;
+  corr U_1, U_2 = 0.09;
+
+  var V_1; stderr 1.1;
+  var V_2; stderr 1.2;
+  var V_3; stderr 1.3;
+
+  var W_1 = 1;
+  var W_2 = 5;
+  var W_3 = 9;
+  var W_1, W_2 = 0.2;
+  var W_1, W_3 = 0.3;
+  var W_2, W_3 = 0.6;
+
+  var f = 3;
+  var f, E_2 = 0.5;
+  corr U_1, f = 0.7;
+end;
+
+stoch_simul(order=1, nodecomposition, irf=0);
+
+L = load('stochastic_matrix_results.mat');
+if max(max(abs(L.oo_.dr.ghu - oo_.dr.ghu))) > 1e-12
+  error('Failure in matrix expansion')
+end
+if max(max(abs(L.oo_.dr.ghx - oo_.dr.ghx))) > 1e-12
+  error('Failure in matrix expansion')
+end
+if max(max(abs(L.oo_.var - oo_.var))) > 1e-12
+  error('Failure in matrix expansion')
+end
diff --git a/tests/pac/.gitignore b/tests/pac/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..77e9e6fc6d184121ec0eda919639e299992b8966
--- /dev/null
+++ b/tests/pac/.gitignore
@@ -0,0 +1,16 @@
+*~
+*.mat
+*.eps
+*.fig
+*.pdf
+*.log
+*.tex
+*_dynamic.m
+*_static.m
+
+*.m
+*.json
+
+checksum
+
+!/run_all_tests.m
diff --git a/tests/pac/README.md b/tests/pac/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a4a302bbdcaee49126298d39b3544647191c299a
--- /dev/null
+++ b/tests/pac/README.md
@@ -0,0 +1,29 @@
+Collection of `*.mod` files for testing the PAC routines in Dynare. To run all the tests sequentially and check that all the `*.mod` files pass the tests, just use the matlab function in the base directory:
+
+```matlab
+>> run_all_tests()
+```
+
+If all goes well, the output should terminate with something like:
+
+```example
+Testsuite results (PAC model):
+
+var-1		             PASS (2.0479s)
+var-2		             PASS (1.9601s)
+var-3		             PASS (1.9826s)
+var-4		             PASS (2.0079s)
+trend-component-1		 PASS (2.2214s)
+trend-component-2		 PASS (2.2195s)
+trend-component-3		 PASS (2.3003s)
+trend-component-4		 PASS (10.5143s)
+trend-component-5		 PASS (2.1538s)
+trend-component-6		 PASS (2.4203s)
+trend-component-7		 PASS (2.7112s)
+trend-component-9		 PASS (2.2164s)
+trend-component-10		 PASS (2.2593s)
+trend-component-11		 PASS (0.69409s)
+trend-component-12		 PASS (2.2663s)
+trend-component-13a		 PASS (0.4119s)
+trend-component-13b		 PASS (0.39554s)
+```
diff --git a/tests/pac/run_all_tests.m b/tests/pac/run_all_tests.m
new file mode 100644
index 0000000000000000000000000000000000000000..2c6d20a3bb7d8c0cdcaa6fa3050b4212ed762748
--- /dev/null
+++ b/tests/pac/run_all_tests.m
@@ -0,0 +1,72 @@
+function run_all_tests()
+
+% Copyright (C) 2018 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/>.
+
+r = [];
+
+r = [r; run_this_test('var-1')];
+r = [r; run_this_test('var-2')];
+r = [r; run_this_test('var-3')];
+r = [r; run_this_test('var-4')];
+
+r = [r; run_this_test('trend-component-1')];
+r = [r; run_this_test('trend-component-2')];
+r = [r; run_this_test('trend-component-3')];
+r = [r; run_this_test('trend-component-4')];
+r = [r; run_this_test('trend-component-5')];
+r = [r; run_this_test('trend-component-6')];
+r = [r; run_this_test('trend-component-7')];
+r = [r; run_this_test('trend-component-9')];
+r = [r; run_this_test('trend-component-10')];
+r = [r; run_this_test('trend-component-11')];
+r = [r; run_this_test('trend-component-12')];
+r = [r; run_this_test('trend-component-13a')];
+r = [r; run_this_test('trend-component-13b')];
+r = [r; run_this_test('trend-component-14')];
+r = [r; run_this_test('trend-component-15')];
+r = [r; run_this_test('trend-component-16')];
+r = [r; run_this_test('trend-component-19-growth-lin-comb')];
+
+print_results(r);
+
+function o = run_this_test(folder)
+try
+    cd(folder)
+    tstart = tic;
+    clear M_ oo_ options_
+    dynare example
+    elapsed = toc(tstart);
+    o = {folder, true, elapsed};
+    system('./clean')
+    cd ..
+catch
+    o = {folder, false, NaN};
+    system('./clean')
+    cd ..
+end
+
+function print_results(r)
+message = sprintf('Testsuite results (PAC model):\n');
+for i = 1:size(r, 1)
+    if r{i,2}
+        message = sprintf('%s\n%s\t\t PASS (%ss)', message, r{i,1}, num2str(r{i,3}));
+    else
+        message = sprintf('%s\n%s\t\t FAILED', message, r{i,1});
+    end
+end
+disp(message)
diff --git a/tests/pac/trend-component-1-mce/clean b/tests/pac/trend-component-1-mce/clean
new file mode 100755
index 0000000000000000000000000000000000000000..4afe51f5f3ef7422f96aed5e9b8d78e7df54c112
--- /dev/null
+++ b/tests/pac/trend-component-1-mce/clean
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+rm *.eps
+
+rm -rf example_det
+rm -rf +example_det
+rm -f example_det*.mat
+rm -f example_det.log
+
+rm -rf example_sto
+rm -rf +example_sto
+rm -f example_sto*.mat
+rm -f example_sto.log
diff --git a/tests/pac/trend-component-1-mce/example_det.mod b/tests/pac/trend-component-1-mce/example_det.mod
new file mode 100644
index 0000000000000000000000000000000000000000..34d1aeda48061a73d7ae4974dd29a9335560f5b6
--- /dev/null
+++ b/tests/pac/trend-component-1-mce/example_det.mod
@@ -0,0 +1,68 @@
+// --+ options: json=compute +--
+
+var x1 x2 x1bar x2bar z ;
+
+varexo ex1 ex2 ex1bar ex2bar ez;
+
+parameters a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta ;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+gamma =  .7;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(discount=beta, model_name=pacman, steady_state_growth=.0);
+
+model;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='eq:pac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+// Initialize the PAC model.
+pac.initialize('pacman');
+
+// Update the PAC/MCE parameters (α in M_.params).
+pac.mce.parameters('pacman');
+
+// Setup a scenario for the shocks.
+shocks;
+   var ex1;
+   periods 1;
+   values .2;
+end;
+
+perfect_foresight_setup(periods=50);
+perfect_foresight_solver;
\ No newline at end of file
diff --git a/tests/pac/trend-component-1-mce/example_sto.mod b/tests/pac/trend-component-1-mce/example_sto.mod
new file mode 100644
index 0000000000000000000000000000000000000000..0a5165938330097f3a04c253043206242e881a2e
--- /dev/null
+++ b/tests/pac/trend-component-1-mce/example_sto.mod
@@ -0,0 +1,71 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z ;
+
+varexo ex1 ex2 ex1bar ex2bar ez;
+
+parameters a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta g;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+gamma =  .7;
+
+g = .02;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(discount=beta, model_name=pacman);
+
+model(linear);
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='eq:pac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+// Initialize the PAC model.
+pac.initialize('pacman');
+
+// Update the PAC/MCE parameters (α in M_.params).
+pac.mce.parameters('pacman');
+
+// Setup a scenario for the shocks.
+shocks;
+var ex1 = .01;
+var ex2 = .01;
+var ex1bar = .0;
+var ex2bar = .0;
+var ez = .02; 
+end;
+
+stoch_simul(periods=1000);
\ No newline at end of file
diff --git a/tests/pac/trend-component-1/clean b/tests/pac/trend-component-1/clean
new file mode 100755
index 0000000000000000000000000000000000000000..be0d5e00cdb49fa48f99aa6470ff0578973bbce3
--- /dev/null
+++ b/tests/pac/trend-component-1/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm -rf +example
+rm -f example*.mat
+rm -f example.log
\ No newline at end of file
diff --git a/tests/pac/trend-component-1/example.mod b/tests/pac/trend-component-1/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..c53a962037098fb1293969fe016dc62e91d5f041
--- /dev/null
+++ b/tests/pac/trend-component-1/example.mod
@@ -0,0 +1,72 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z ;
+
+varexo ex1 ex2 ex1bar ex2bar ez ;
+
+parameters a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta ;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+gamma =  .7;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='eq:pac']
+diff(z) = gamma*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-gamma)*ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
diff --git a/tests/pac/trend-component-10/clean b/tests/pac/trend-component-10/clean
new file mode 100755
index 0000000000000000000000000000000000000000..bdc7da19ab956a4a155e5fc8cbdf9a11ebbebff0
--- /dev/null
+++ b/tests/pac/trend-component-10/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
\ No newline at end of file
diff --git a/tests/pac/trend-component-10/example.mod b/tests/pac/trend-component-10/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..d1e12cef98a7c4f18e6fbb158c9c0332857aa40c
--- /dev/null
+++ b/tests/pac/trend-component-10/example.mod
@@ -0,0 +1,95 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(log(x1)) = a_x1_0*(log(x1(-1))-x1bar(-1)) + a_x1_1*diff(log(x1(-1))) + a_x1_2*diff(log(x1(-2))) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(log(x1(-1))) + a_x2_2*diff(log(x1(-2))) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(log(x1(-1))-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = .1;
+    var ex2bar = .1;
+    var ez = 1.0;
+    var ey = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+INITIALCONDITIONS = zeros(10, M_.endo_nbr+M_.exo_nbr);
+INITIALCONDITIONS(:,1) = ones(10, 1);
+initialconditions = dseries(INITIALCONDITIONS, 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 300);
+
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m = .9;
+eparams.c_z_1 = .5;
+eparams.c_z_2 = .2;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2000Q1+200);
+
+disp(sprintf('Estimate of e_c_m: %f', M_.params(strmatch('e_c_m', M_.param_names, 'exact'))))
+disp(sprintf('Estimate of c_z_1: %f', M_.params(strmatch('c_z_1', M_.param_names, 'exact'))))
+disp(sprintf('Estimate of c_z_2: %f', M_.params(strmatch('c_z_2', M_.param_names, 'exact'))))
diff --git a/tests/pac/trend-component-11/clean b/tests/pac/trend-component-11/clean
new file mode 100755
index 0000000000000000000000000000000000000000..2935a38ad605cee3810c18217e54906355524374
--- /dev/null
+++ b/tests/pac/trend-component-11/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example*.mat
+rm -f example.log
\ No newline at end of file
diff --git a/tests/pac/trend-component-11/example.mod b/tests/pac/trend-component-11/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..28095291e9d28ca17f0986ad9c603a37c3b3ecce
--- /dev/null
+++ b/tests/pac/trend-component-11/example.mod
@@ -0,0 +1,74 @@
+// --+ options: json=compute, transform_unary_ops, stochastic +--
+
+var x1 x2 x1bar x2bar z ;
+
+varexo ex1 ex2 ex1bar ex2bar ez ;
+
+parameters a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta ;
+
+a_x1_0 =  -.9999;
+a_x1_1 =  .4;
+a_x1_2 =  0;//.3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = 0;//.2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  0;//-.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = 0;//.2;
+
+beta  =  .1;
+e_c_m =  .1;
+c_z_1 =  .07;
+c_z_2 = -.3;
+
+gamma =  .7;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar',  'eq:x2bar'], targets=['eq:x1bar',  'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:x1']
+diff(diff(log(x1))) = a_x1_0*(diff(log(x1(-1)))-x1bar(-1)) + a_x1_1*diff(diff(log(x1(-1)))) + a_x1_2*diff(diff(x1(-2))) + a_x1_x2_1*diff(log(x2(-1))) + a_x1_x2_2*diff(log(x2(-2))) + ex1;     
+
+[name='eq:x2']
+diff(log(x2)) = a_x2_0*(log(x2(-1))-x2bar(-1)) + a_x2_1*diff(diff(log(x1(-1)))) + a_x2_2*diff(diff(log(x1(-2)))) + a_x2_x1_1*diff(log(x2(-1))) + a_x2_x1_2*diff(log(x2(-2))) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='eq:pac']
+diff(z) = gamma*(e_c_m*(log(x1(-1))-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-gamma)*ez;
+
+
+end;
+
+shocks;
+    var ex1 = 1;
+    var ex2 = 1;
+    var ex1bar = .1;
+    var ex2bar = .11;
+    var ez = 1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero for non logged variables, and one for logged variables
+init = .1*ones(10,M_.endo_nbr+M_.exo_nbr);
+initialconditions = dseries(init, 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 10);
diff --git a/tests/pac/trend-component-12/clean b/tests/pac/trend-component-12/clean
new file mode 100755
index 0000000000000000000000000000000000000000..bdc7da19ab956a4a155e5fc8cbdf9a11ebbebff0
--- /dev/null
+++ b/tests/pac/trend-component-12/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
\ No newline at end of file
diff --git a/tests/pac/trend-component-12/example.mod b/tests/pac/trend-component-12/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..f0749985faf2df7cc109f9a3adf854a77182e35e
--- /dev/null
+++ b/tests/pac/trend-component-12/example.mod
@@ -0,0 +1,105 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey g;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta ;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, growth=g, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var g = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+B = 1;
+X = zeros(3,B);
+
+set_dynare_seed('default');
+options_.bnlms.set_dynare_seed_to_default = false;
+
+for i=1:B
+    e_c_m =  .5;
+    c_z_1 =  .2;
+    c_z_2 = -.1;
+    // Simulate the model for 500 periods
+    TrueData = simul_backward_model(initialconditions, 300);
+    // Define a structure describing the parameters to be estimated (with initial conditions). 
+    clear eparams
+    eparams.e_c_m = .5;
+    eparams.c_z_1 = .2;
+    eparams.c_z_2 =-.1;
+    // Define the dataset used for estimation
+    edata = TrueData;
+    edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+    pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2000Q1+200);
+    X(1,i) = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+    X(2,i) = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+    X(3,i) = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+end
+
+mean(X, 2)
diff --git a/tests/pac/trend-component-13a/clean b/tests/pac/trend-component-13a/clean
new file mode 100755
index 0000000000000000000000000000000000000000..bdc7da19ab956a4a155e5fc8cbdf9a11ebbebff0
--- /dev/null
+++ b/tests/pac/trend-component-13a/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
\ No newline at end of file
diff --git a/tests/pac/trend-component-13a/example.mod b/tests/pac/trend-component-13a/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..da102a915ed68faca2e5c943d557f5f3772d316f
--- /dev/null
+++ b/tests/pac/trend-component-13a/example.mod
@@ -0,0 +1,74 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey g;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta ;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, growth=g, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var g = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+if ~isequal(M_.pac.pacman.equations.(M_.pac.pacman.tag_map{strcmp(M_.pac.pacman.tag_map(:,1), 'zpac'),2}).ec.istarget, [true, false])
+   error('ec.istarget vector is wrong.')
+end
diff --git a/tests/pac/trend-component-13b/clean b/tests/pac/trend-component-13b/clean
new file mode 100755
index 0000000000000000000000000000000000000000..bdc7da19ab956a4a155e5fc8cbdf9a11ebbebff0
--- /dev/null
+++ b/tests/pac/trend-component-13b/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
\ No newline at end of file
diff --git a/tests/pac/trend-component-13b/example.mod b/tests/pac/trend-component-13b/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..da102a915ed68faca2e5c943d557f5f3772d316f
--- /dev/null
+++ b/tests/pac/trend-component-13b/example.mod
@@ -0,0 +1,74 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey g;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta ;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, growth=g, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var g = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+if ~isequal(M_.pac.pacman.equations.(M_.pac.pacman.tag_map{strcmp(M_.pac.pacman.tag_map(:,1), 'zpac'),2}).ec.istarget, [true, false])
+   error('ec.istarget vector is wrong.')
+end
diff --git a/tests/pac/trend-component-14/clean b/tests/pac/trend-component-14/clean
new file mode 100755
index 0000000000000000000000000000000000000000..4ca44cac853dd69f009110c0ff32d500efe8423a
--- /dev/null
+++ b/tests/pac/trend-component-14/clean
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -rf substitution
+rm  -rf +substitution
+rm -f substitution.log
diff --git a/tests/pac/trend-component-14/example.mod b/tests/pac/trend-component-14/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..d1dff12d81caf95805627e265e443838756d972a
--- /dev/null
+++ b/tests/pac/trend-component-14/example.mod
@@ -0,0 +1,93 @@
+// --+ options: transform_unary_ops, json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+set_dynare_seed('default');
+TrueData = simul_backward_model(initialconditions, 300);
+
+// Print expanded PAC_EXPECTATION term.
+pac.print('pacman', 'zpac');
+
+verbatim;
+  set_dynare_seed('default');
+  y = zeros(M_.endo_nbr,1);
+  y(1:M_.orig_endo_nbr) = rand(M_.orig_endo_nbr, 1);
+  x = randn(M_.exo_nbr,1);
+  y = example.set_auxiliary_variables(y, x, M_.params);
+  y = [y(find(M_.lead_lag_incidence(1,:))); y];
+  [residual, g1] = example.dynamic(y, x', M_.params, oo_.steady_state, 1);
+  save('example.mat', 'residual', 'g1', 'TrueData');
+end;
\ No newline at end of file
diff --git a/tests/pac/trend-component-14/substitution.mod b/tests/pac/trend-component-14/substitution.mod
new file mode 100644
index 0000000000000000000000000000000000000000..6070b5b2af4f6189a064dce36c1f7b1774315632
--- /dev/null
+++ b/tests/pac/trend-component-14/substitution.mod
@@ -0,0 +1,98 @@
+// --+ options: transform_unary_ops, json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+@#include "example/model/pac-expectations/eq0-pacman-parameters.inc"
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) +
+@#include "example/model/pac-expectations/eq0-pacman-expression.inc"
++ ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+end;
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+set_dynare_seed('default');
+TrueData = simul_backward_model(initialconditions, 300);
+
+verbatim;
+  set_dynare_seed('default');
+  y = zeros(M_.endo_nbr,1);
+  y(1:M_.orig_endo_nbr) = rand(M_.orig_endo_nbr, 1);
+  x = randn(M_.exo_nbr,1);
+  y = substitution.set_auxiliary_variables(y, x, M_.params);
+  y = [y(find(M_.lead_lag_incidence(1,:))); y];
+  example = load('example.mat');
+  [residual, g1] = substitution.dynamic(y, x', M_.params, oo_.steady_state, 1);
+end;
+
+if max(abs(example.TrueData.data(:)-TrueData.data(:)))>1e-9
+   error('Simulations do not match.')
+end
+
+if ~isequal(length(residual), length(example.residual)) || max(abs(example.residual-residual))>1e-8
+  warning('Residuals do not match!')
+end
+
+if ~isequal(length(g1(:)), length(example.g1(:))) || max(abs(example.g1(:)-g1(:)))>1e-8
+  warning('Jacobian matrices do not match!')
+end
+
+delete('example.mat');
\ No newline at end of file
diff --git a/tests/pac/trend-component-15/clean b/tests/pac/trend-component-15/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-15/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-15/example.mod b/tests/pac/trend-component-15/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..7d2786ccba660a71d7c430d6f69b90a44c12163d
--- /dev/null
+++ b/tests/pac/trend-component-15/example.mod
@@ -0,0 +1,138 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+lambda = .5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*( y + x) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var ex = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 5000);
+
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m =  .9;
+eparams.c_z_1 =  .5;
+eparams.c_z_2 =  .2;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2005Q1+4000);
+
+e_c_m_iterative_ols = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_iterative_ols = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_iterative_ols = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_iterative_ols))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_iterative_ols))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_iterative_ols))
+
+skipline(2)
+
+clear eparams
+eparams.e_c_m =  .9;
+eparams.c_z_1 =  .5;
+eparams.c_z_2 =  .2;
+
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2005Q1+4000, 'fminunc');
+
+e_c_m_nls = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_nls = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_nls = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_nls))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_nls))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_nls))
+
+if abs(e_c_m_nls-e_c_m_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (e_c_m)')
+end
+
+if abs(c_z_1_nls-c_z_1_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_1)')
+end
+
+if abs(c_z_2_nls-c_z_2_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_2)')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-16/clean b/tests/pac/trend-component-16/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-16/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-16/example.mod b/tests/pac/trend-component-16/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..1afaf9589bbd6f5f66fa380a8724bc37ffa676f7
--- /dev/null
+++ b/tests/pac/trend-component-16/example.mod
@@ -0,0 +1,151 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*( y + x) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var ex = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 5000);
+
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m  =  .9;
+eparams.c_z_1  =  .5;
+eparams.c_z_2  =  .2;
+eparams.lambda =  .7;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2005Q1+4000);
+
+e_c_m_iterative_ols = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_iterative_ols = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_iterative_ols = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+lambda_iterative_ols = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_iterative_ols))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_iterative_ols))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_iterative_ols))
+disp(sprintf('Estimate of lambda: %f', lambda_iterative_ols))
+
+skipline(2)
+
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m  =  .9;
+eparams.c_z_1  =  .5;
+eparams.c_z_2  =  .2;
+eparams.lambda =  .7;
+
+
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2005Q1+4000, 'fmincon');
+
+
+e_c_m_nls = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_nls = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_nls = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+lambda_nls = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_nls))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_nls))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_nls))
+disp(sprintf('Estimate of lambda: %f', lambda_nls))
+
+if abs(e_c_m_nls-e_c_m_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (e_c_m)')
+end
+
+if abs(c_z_1_nls-c_z_1_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_1)')
+end
+
+if abs(c_z_2_nls-c_z_2_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_2)')
+end
+
+if abs(lambda_nls-lambda_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (lambda)')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-17/clean b/tests/pac/trend-component-17/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-17/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-17/example.mod b/tests/pac/trend-component-17/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..bb65036e7c3635c23dfeb6f0419c46bffcc996cc
--- /dev/null
+++ b/tests/pac/trend-component-17/example.mod
@@ -0,0 +1,160 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*( y + x) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var ex = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 300);
+
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m  =  .9;
+eparams.c_z_1  =  .5;
+eparams.c_z_2  =  .2;
+eparams.lambda =  .7;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+
+tic
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2005Q1+200, 'csminwel', 'verbosity', 0);
+toc
+skipline(1)
+
+e_c_m_nls = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_nls = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_nls = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+lambda_nls = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_nls))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_nls))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_nls))
+disp(sprintf('Estimate of lambda: %f', lambda_nls))
+
+skipline(2)
+
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m  =  .9;
+eparams.c_z_1  =  .5;
+eparams.c_z_2  =  .2;
+eparams.lambda =  .0;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+
+tic
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2005Q1+200, 'GaussNewton');
+toc
+
+skipline(1)
+
+e_c_m_gauss_newton = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_gauss_newton = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_gauss_newton= M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+lambda_gauss_newton = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_gauss_newton))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_gauss_newton))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_gauss_newton))
+disp(sprintf('Estimate of lambda: %f', lambda_gauss_newton))
+
+if abs(e_c_m_nls-e_c_m_gauss_newton)>.01
+   error('Gauss Newton and direct SSR minimization do not provide consistent estimates (e_c_m)')
+end
+
+if abs(c_z_1_nls-c_z_1_gauss_newton)>.01
+   error('Gauss Newton and direct SSR minimization do not provide consistent estimates (c_z_1)')
+end
+
+if abs(c_z_2_nls-c_z_2_gauss_newton)>.01
+   error('Gauss Newton and direct SSR minimization do not provide consistent estimates (c_z_2)')
+end
+
+if abs(lambda_nls-lambda_gauss_newton)>.01
+   error('Gauss Newton and direct SSR minimization do not provide consistent estimates (lambda)')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-18/clean b/tests/pac/trend-component-18/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-18/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-18/example.mod b/tests/pac/trend-component-18/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..26418c850e9df4f0cdcc7a8125b4fb6bced2c3f2
--- /dev/null
+++ b/tests/pac/trend-component-18/example.mod
@@ -0,0 +1,159 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*( y + x) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var ex = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 300);
+
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m  =  .9;
+eparams.c_z_1  =  .5;
+eparams.c_z_2  =  .2;
+eparams.lambda =  .7;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+
+tic
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2005Q1+200, 'csminwel', 'verbosity', 0);
+toc
+skipline(1)
+
+e_c_m_nls = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_nls = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_nls = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+lambda_nls = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_nls))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_nls))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_nls))
+disp(sprintf('Estimate of lambda: %f', lambda_nls))
+
+skipline(2)
+
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m  =  .9;
+eparams.c_z_1  =  .5;
+eparams.c_z_2  =  .2;
+eparams.lambda =  .0;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+
+tic
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2005Q1+200, 'lsqnonlin', 'Algorithm', 'levenberg-marquardt');
+toc
+
+skipline(1)
+
+e_c_m_lsqnonlin = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_lsqnonlin = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_lsqnonlin= M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+lambda_lsqnonlin = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_lsqnonlin))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_lsqnonlin))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_lsqnonlin))
+disp(sprintf('Estimate of lambda: %f', lambda_lsqnonlin))
+
+if abs(e_c_m_nls-e_c_m_lsqnonlin)>.01
+   error('Gauss Newton and direct SSR minimization do not provide consistent estimates (e_c_m)')
+end
+
+if abs(c_z_1_nls-c_z_1_lsqnonlin)>.01
+   error('Gauss Newton and direct SSR minimization do not provide consistent estimates (c_z_1)')
+end
+
+if abs(c_z_2_nls-c_z_2_lsqnonlin)>.01
+   error('Gauss Newton and direct SSR minimization do not provide consistent estimates (c_z_2)')
+end
+
+if abs(lambda_nls-lambda_lsqnonlin)>.01
+   error('Gauss Newton and direct SSR minimization do not provide consistent estimates (lambda)')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-19-growth-lin-comb/clean b/tests/pac/trend-component-19-growth-lin-comb/clean
new file mode 100644
index 0000000000000000000000000000000000000000..c0a4ee970df4ea508d4ad14942bbda3bdd820e51
--- /dev/null
+++ b/tests/pac/trend-component-19-growth-lin-comb/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
\ No newline at end of file
diff --git a/tests/pac/trend-component-19-growth-lin-comb/example.mod b/tests/pac/trend-component-19-growth-lin-comb/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..6a6a9cef96cdcfbf59fa869220bb9ce65589906d
--- /dev/null
+++ b/tests/pac/trend-component-19-growth-lin-comb/example.mod
@@ -0,0 +1,131 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y gg;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey g;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta ;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, growth=0.5*gg(-1)+beta+ex1, model_name=pacman);
+
+model;
+
+[name='eq:gg']
+gg = g;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 5000 periods
+TrueData = simul_backward_model(initialconditions, 5000);
+
+// NLS estimation
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m = .5;
+eparams.c_z_1 = .2;
+eparams.c_z_2 =-.1;
+
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2000Q1+200, 'lsqnonlin');
+
+e_c_m_nls = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_nls = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_nls = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+resid_nls = oo_.pac.pacman.equations.eq0.residual;
+
+fprintf('Estimate of e_c_m: %f \n', e_c_m_nls)
+fprintf('Estimate of c_z_1: %f \n', c_z_1_nls)
+fprintf('Estimate of c_z_2: %f \n', c_z_2_nls)
+
+skipline(2)
+
+// Iterative OLS estimation using estimates from NLS
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m = e_c_m_nls;
+eparams.c_z_1 = c_z_1_nls;
+eparams.c_z_2 = c_z_2_nls;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2000Q1+200);
+
+// Test printing of PAC expectations
+pac.print('pacman','zpac');
+
+// Print equations where the variable appears in
+fprintf('x1bar is in: \n')
+print_equations('x1bar')
+fprintf('\n')
+
+fprintf('x2bar is in: \n')
+print_equations('x2bar', true);
+fprintf('\n')
+
+e_c_m_iterative_ols = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_iterative_ols = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_iterative_ols = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+resid_iterative_ols = oo_.pac.pacman.equations.eq0.residual;
+
+fprintf('Estimate of e_c_m: %f \n', e_c_m_iterative_ols)
+fprintf('Estimate of c_z_1: %f \n', c_z_1_iterative_ols)
+fprintf('Estimate of c_z_2: %f \n', c_z_2_iterative_ols)
+
+if any(abs(resid_nls-resid_iterative_ols)>1e-4)
+   error('Iterative OLS and NLS do not provide consistent results.')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-19/clean b/tests/pac/trend-component-19/clean
new file mode 100755
index 0000000000000000000000000000000000000000..352d176922155619713aa70b4c3ed1eabe28d477
--- /dev/null
+++ b/tests/pac/trend-component-19/clean
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+rm -rf example1 example2 example3
+rm  -rf +example1 +example2 +example3
+
+rm -f *.log
+rm -f *.mat H.dat
diff --git a/tests/pac/trend-component-19/example1.mod b/tests/pac/trend-component-19/example1.mod
new file mode 100644
index 0000000000000000000000000000000000000000..b1d019ba4bb5293ec4feaffcb40880bc0ba697bb
--- /dev/null
+++ b/tests/pac/trend-component-19/example1.mod
@@ -0,0 +1,108 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y gg;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey g;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta ;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, growth=gg(-1), model_name=pacman);
+
+model;
+
+[name='eq:gg']
+gg = g;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var g = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+B = 1;
+X = zeros(3,B);
+
+set_dynare_seed('default');
+options_.bnlms.set_dynare_seed_to_default = false;
+
+for i=1:B
+    e_c_m =  .5;
+    c_z_1 =  .2;
+    c_z_2 = -.1;
+    // Simulate the model for 500 periods
+    TrueData = simul_backward_model(initialconditions, 300);
+    // Define a structure describing the parameters to be estimated (with initial conditions). 
+    clear eparams
+    eparams.e_c_m = .5;
+    eparams.c_z_1 = .2;
+    eparams.c_z_2 =-.1;
+    // Define the dataset used for estimation
+    edata = TrueData;
+    edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+    pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2000Q1+200);
+    X(1,i) = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+    X(2,i) = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+    X(3,i) = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+end
+
+mean(X, 2)
diff --git a/tests/pac/trend-component-19/example2.mod b/tests/pac/trend-component-19/example2.mod
new file mode 100644
index 0000000000000000000000000000000000000000..8fdb2ce9e1adbeaf91bd0fe2f64b1ffc99ed8323
--- /dev/null
+++ b/tests/pac/trend-component-19/example2.mod
@@ -0,0 +1,107 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y gg;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey g;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta ;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, growth=gg(-2), model_name=pacman);
+
+model;
+
+[name='eq:gg']
+gg = g;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var g = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+B = 1;
+X = zeros(3,B);
+
+set_dynare_seed('default');
+options_.bnlms.set_dynare_seed_to_default = false;
+
+for i=1:B
+    e_c_m =  .5;
+    c_z_1 =  .2;
+    c_z_2 = -.1;
+    // Simulate the model for 500 periods
+    TrueData = simul_backward_model(initialconditions, 300);
+    // Define a structure describing the parameters to be estimated (with initial conditions). 
+    clear eparams
+    eparams.e_c_m = .5;
+    eparams.c_z_1 = .2;
+    eparams.c_z_2 =-.1;
+    // Define the dataset used for estimation
+    edata = TrueData;
+    edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+    pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2000Q1+200);
+    X(1,i) = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+    X(2,i) = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+    X(3,i) = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+end
+
+mean(X, 2)
diff --git a/tests/pac/trend-component-19/example3.mod b/tests/pac/trend-component-19/example3.mod
new file mode 100644
index 0000000000000000000000000000000000000000..86ed929dac4d1e0f31e5412db84f831128beb710
--- /dev/null
+++ b/tests/pac/trend-component-19/example3.mod
@@ -0,0 +1,108 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y gg;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey g;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta ;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, growth=gg(-3), model_name=pacman);
+
+model;
+
+[name='eq:gg']
+gg = g;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var g = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+B = 1;
+X = zeros(3,B);
+
+set_dynare_seed('default');
+options_.bnlms.set_dynare_seed_to_default = false;
+
+for i=1:B
+    e_c_m =  .5;
+    c_z_1 =  .2;
+    c_z_2 = -.1;
+    // Simulate the model for 500 periods
+    TrueData = simul_backward_model(initialconditions, 300);
+    // Define a structure describing the parameters to be estimated (with initial conditions). 
+    clear eparams
+    eparams.e_c_m = .5;
+    eparams.c_z_1 = .2;
+    eparams.c_z_2 =-.1;
+    // Define the dataset used for estimation
+    edata = TrueData;
+    edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+    pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2000Q1+200);
+    X(1,i) = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+    X(2,i) = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+    X(3,i) = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+end
+
+mean(X, 2)
diff --git a/tests/pac/trend-component-2-mce/clean b/tests/pac/trend-component-2-mce/clean
new file mode 100755
index 0000000000000000000000000000000000000000..4afe51f5f3ef7422f96aed5e9b8d78e7df54c112
--- /dev/null
+++ b/tests/pac/trend-component-2-mce/clean
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+rm *.eps
+
+rm -rf example_det
+rm -rf +example_det
+rm -f example_det*.mat
+rm -f example_det.log
+
+rm -rf example_sto
+rm -rf +example_sto
+rm -f example_sto*.mat
+rm -f example_sto.log
diff --git a/tests/pac/trend-component-2-mce/example_det.mod b/tests/pac/trend-component-2-mce/example_det.mod
new file mode 100644
index 0000000000000000000000000000000000000000..638fcf21a11d861bc5d88c6064d5456aa849ffb3
--- /dev/null
+++ b/tests/pac/trend-component-2-mce/example_det.mod
@@ -0,0 +1,74 @@
+// --+ options: json=compute +--
+
+var x1 x2 x1bar x2bar z y1 y2;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey1 ey2;
+
+parameters a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta ;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+          a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+gamma =  .7;    
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:exo:1']
+diff(y1) = .7*diff(y1(-1)) - .3*diff(y1(-2)) + ey1;
+
+[name='eq:exo:2']
+diff(y2) = .5*diff(y2(-1)) - .2*diff(y2(-3)) + ey2;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='eq:pac']
+diff(z) = gamma*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1)) + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-gamma)*(.5*diff(y1)-.7*diff(y2)) + ez;
+
+end;
+
+// Initialize the PAC model.
+pac.initialize('pacman');
+
+// Update the PAC/MCE parameters (α in M_.params).
+pac.mce.parameters('pacman');
+
+// Setup a scenario for the shocks.
+shocks;
+   var ex1;
+   periods 1;
+   values .2;
+end;
+
+perfect_foresight_setup(periods=50);
+perfect_foresight_solver;
\ No newline at end of file
diff --git a/tests/pac/trend-component-2-mce/example_sto.mod b/tests/pac/trend-component-2-mce/example_sto.mod
new file mode 100644
index 0000000000000000000000000000000000000000..89c3f81ccf65c476c9289d9c5f2caa2334664c4c
--- /dev/null
+++ b/tests/pac/trend-component-2-mce/example_sto.mod
@@ -0,0 +1,77 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y1 y2;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey1 ey2;
+
+parameters a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta ;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+gamma =  .7;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(discount=beta, model_name=pacman, steady_state_growth=.0);
+
+model(linear);
+
+[name='eq:exo:1']
+diff(y1) = .7*diff(y1(-1)) - .3*diff(y1(-2)) + ey1;
+
+[name='eq:exo:2']
+diff(y2) = .5*diff(y2(-1)) - .2*diff(y2(-3)) + ey2;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='eq:pac']
+diff(z) = gamma*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1)) + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-gamma)*(.5*diff(y1)-.7*diff(y2)) + ez;
+
+end;
+
+// Initialize the PAC model.
+pac.initialize('pacman');
+
+// Update the PAC/MCE parameters (α in M_.params).
+pac.mce.parameters('pacman');
+
+// Setup a scenario for the shocks.
+shocks;
+var ex1 = .01;
+var ex2 = .01;
+var ey1 = .005;
+var ey2 = .007;
+var ex1bar = .0;
+var ex2bar = .0;
+var ez = .02; 
+end;
+
+stoch_simul(periods=1000, noprint);
\ No newline at end of file
diff --git a/tests/pac/trend-component-2/clean b/tests/pac/trend-component-2/clean
new file mode 100755
index 0000000000000000000000000000000000000000..be0d5e00cdb49fa48f99aa6470ff0578973bbce3
--- /dev/null
+++ b/tests/pac/trend-component-2/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm -rf +example
+rm -f example*.mat
+rm -f example.log
\ No newline at end of file
diff --git a/tests/pac/trend-component-2/example.mod b/tests/pac/trend-component-2/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..c1029d742e4bb5a43d452086117416bb09f5be4b
--- /dev/null
+++ b/tests/pac/trend-component-2/example.mod
@@ -0,0 +1,73 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z ;
+
+varexo ex1 ex2 ex1bar ex2bar ez ;
+
+parameters a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta ;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .1;
+e_c_m =  .1;
+c_z_1 =  .07;
+c_z_2 = -.3;
+
+gamma =  .7;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar',  'eq:x2bar'], targets=['eq:x1bar',  'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:x1']
+diff(diff(x1)) = a_x1_0*(diff(x1(-1))-diff(x1bar(-1))) + a_x1_1*diff(diff(x1(-1))) + a_x1_2*diff(diff(x1(-2))) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(diff(x1(-1))) + a_x2_2*diff(diff(x1(-2))) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+diff(x1bar) = diff(x1bar(-1)) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='eq:pac']
+diff(z) = gamma*( e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-gamma)*ez;
+
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
diff --git a/tests/pac/trend-component-20-1/clean b/tests/pac/trend-component-20-1/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-20-1/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-20-1/example.mod b/tests/pac/trend-component-20-1/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..a0a6daaf21cc1b8542a8020a6a693a5d8eac2783
--- /dev/null
+++ b/tests/pac/trend-component-20-1/example.mod
@@ -0,0 +1,72 @@
+// --+ options: json=compute, stochastic +--
+
+// Check that the content of pac.[pacmodel].equations.[eqtag].non_optimizing_behaviour.vars is correct.
+
+var x1 x2 x1bar x2bar z y x;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*( y + x) + ez;
+
+end;
+
+if ~isequal(M_.endo_names(M_.pac.pacman.equations.eq0.non_optimizing_behaviour.vars), {'y'; 'x'})
+   error('PAC non_optimizing_behaviour.vars field is wrong.')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-20-2/clean b/tests/pac/trend-component-20-2/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-20-2/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-20-2/example.mod b/tests/pac/trend-component-20-2/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..7406c04e0fc3c867831a8b65008ac64e68544ade
--- /dev/null
+++ b/tests/pac/trend-component-20-2/example.mod
@@ -0,0 +1,72 @@
+// --+ options: json=compute, stochastic +--
+
+// Check that the content of pac.[pacmodel].equations.[eqtag].non_optimizing_behaviour.vars is correct.
+
+var x1 x2 x x1bar x2bar y z ;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*( y + x) + ez;
+
+end;
+
+if ~isequal(M_.endo_names(M_.pac.pacman.equations.eq0.non_optimizing_behaviour.vars), {'y'; 'x'})
+   error('PAC non_optimizing_behaviour.vars field is wrong.')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-20-3/clean b/tests/pac/trend-component-20-3/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-20-3/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-20-3/example.mod b/tests/pac/trend-component-20-3/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..051470fdc40aa9a077f7c989be48c3976fe0054c
--- /dev/null
+++ b/tests/pac/trend-component-20-3/example.mod
@@ -0,0 +1,72 @@
+// --+ options: json=compute, stochastic +--
+
+// Check that the content of pac.[pacmodel].equations.[eqtag].non_optimizing_behaviour.vars is correct.
+
+var x1 x2 x x1bar x2bar y z ;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*( y + x) + ez;
+
+end;
+
+if ~isequal(M_.endo_names(M_.pac.pacman.equations.eq0.non_optimizing_behaviour.vars), {'y'; 'x'})
+   error('PAC non_optimizing_behaviour.vars field is wrong.')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-20-4/clean b/tests/pac/trend-component-20-4/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-20-4/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-20-4/example.mod b/tests/pac/trend-component-20-4/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..284d88b2c088cb7f492ea87449bcbe2c17553ef7
--- /dev/null
+++ b/tests/pac/trend-component-20-4/example.mod
@@ -0,0 +1,72 @@
+// --+ options: json=compute, stochastic +--
+
+// Check that the content of pac.[pacmodel].equations.[eqtag].non_optimizing_behaviour.vars is correct.
+
+var x1 x2 x1bar x2bar z y x;
+
+varexo ex1 tt ex2 ex1bar ex2bar ez ey ex;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*(y + x + tt) + ez;
+
+end;
+
+if ~isequal([M_.endo_names(M_.pac.pacman.equations.eq0.non_optimizing_behaviour.vars(M_.pac.pacman.equations.eq0.non_optimizing_behaviour.isendo)); M_.exo_names(M_.pac.pacman.equations.eq0.non_optimizing_behaviour.vars(~M_.pac.pacman.equations.eq0.non_optimizing_behaviour.isendo))], {'y'; 'x'; 'tt'})
+   error('PAC non_optimizing_behaviour.vars and/or non_optimizing_behaviour.isendo fields are wrong.')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-21/clean b/tests/pac/trend-component-21/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-21/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-21/example.mod b/tests/pac/trend-component-21/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..d127a0db82cf99d99e66ae5a5b41c2191bbee677
--- /dev/null
+++ b/tests/pac/trend-component-21/example.mod
@@ -0,0 +1,160 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*( y + x) + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var ex = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 5000);
+
+// Define a structure describing the parameters to be estimated (with initial conditions).
+clear eparams
+eparams.e_c_m   =  .9;
+eparams.c_z_1   =  .5;
+eparams.c_z_2   =  .2;
+eparams.c_z_dx2 =  .5;
+eparams.lambda  =  .7;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2005Q1+4000);
+
+e_c_m_iterative_ols = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_iterative_ols = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_iterative_ols = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+c_z_dx2_iterative_ols = M_.params(strmatch('c_z_dx2', M_.param_names, 'exact'));
+lambda_iterative_ols = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_iterative_ols))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_iterative_ols))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_iterative_ols))
+disp(sprintf('Estimate of c_z_dx2: %f', c_z_dx2_iterative_ols))
+disp(sprintf('Estimate of lambda: %f', lambda_iterative_ols))
+
+skipline(2)
+
+// Define a structure describing the parameters to be estimated (with initial conditions).
+clear eparams
+eparams.e_c_m   =  .9;
+eparams.c_z_1   =  .5;
+eparams.c_z_2   =  .2;
+eparams.c_z_dx2 =  .5;
+eparams.lambda  =  .7;
+
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2005Q1+4000, 'fmincon');
+
+e_c_m_nls = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_nls = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_nls = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+c_z_dx2_nls = M_.params(strmatch('c_z_dx2', M_.param_names, 'exact'));
+lambda_nls = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_nls))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_nls))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_nls))
+disp(sprintf('Estimate of c_z_dx2: %f', c_z_dx2_nls))
+disp(sprintf('Estimate of lambda: %f', lambda_nls))
+
+if abs(e_c_m_nls-e_c_m_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (e_c_m)')
+end
+
+if abs(c_z_1_nls-c_z_1_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_1)')
+end
+
+if abs(c_z_2_nls-c_z_2_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_2)')
+end
+
+if abs(c_z_dx2_nls-c_z_dx2_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_dx2)')
+end
+
+if abs(lambda_nls-lambda_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (lambda)')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-22/clean b/tests/pac/trend-component-22/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-22/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-22/example.mod b/tests/pac/trend-component-22/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..1f8d36b474fe5b9c744a6b851911e013c8e36580
--- /dev/null
+++ b/tests/pac/trend-component-22/example.mod
@@ -0,0 +1,150 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*( y + x) + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var ex = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 5000);
+
+// Define a structure describing the parameters to be estimated (with initial conditions).
+clear eparams
+eparams.e_c_m   =  .9;
+eparams.c_z_1   =  .5;
+eparams.c_z_2   =  .2;
+eparams.c_z_dx2 =  .5;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2005Q1+4000);
+
+e_c_m_iterative_ols = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_iterative_ols = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_iterative_ols = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+c_z_dx2_iterative_ols = M_.params(strmatch('c_z_dx2', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_iterative_ols))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_iterative_ols))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_iterative_ols))
+disp(sprintf('Estimate of c_z_dx2: %f', c_z_dx2_iterative_ols))
+
+skipline(2)
+
+// Define a structure describing the parameters to be estimated (with initial conditions).
+clear eparams
+eparams.e_c_m   =  .9;
+eparams.c_z_1   =  .5;
+eparams.c_z_2   =  .2;
+eparams.c_z_dx2 =  .5;
+
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2005Q1+4000, 'fmincon');
+
+e_c_m_nls = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_nls = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_nls = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+c_z_dx2_nls = M_.params(strmatch('c_z_dx2', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_nls))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_nls))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_nls))
+disp(sprintf('Estimate of c_z_dx2: %f', c_z_dx2_nls))
+
+if abs(e_c_m_nls-e_c_m_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (e_c_m)')
+end
+
+if abs(c_z_1_nls-c_z_1_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_1)')
+end
+
+if abs(c_z_2_nls-c_z_2_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_2)')
+end
+
+if abs(c_z_dx2_nls-c_z_dx2_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_dx2)')
+end
diff --git a/tests/pac/trend-component-23/clean b/tests/pac/trend-component-23/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-23/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-23/example.mod b/tests/pac/trend-component-23/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..c299ab6ce12db41aace476adcb747659b2aba422
--- /dev/null
+++ b/tests/pac/trend-component-23/example.mod
@@ -0,0 +1,165 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x u;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex eu;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*( y + x) + c_z_dx2*diff(x2) + c_z_u*u + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var ex = 0.1;
+    var eu = 0.05;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 5000);
+
+// Define a structure describing the parameters to be estimated (with initial conditions).
+clear eparams
+eparams.e_c_m   =  .9;
+eparams.c_z_1   =  .5;
+eparams.c_z_2   =  .2;
+eparams.c_z_dx2 =  .5;
+eparams.lambda  =  .7;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2005Q1+4000);
+
+e_c_m_iterative_ols = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_iterative_ols = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_iterative_ols = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+c_z_dx2_iterative_ols = M_.params(strmatch('c_z_dx2', M_.param_names, 'exact'));
+lambda_iterative_ols = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_iterative_ols))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_iterative_ols))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_iterative_ols))
+disp(sprintf('Estimate of c_z_dx2: %f', c_z_dx2_iterative_ols))
+disp(sprintf('Estimate of lambda: %f', lambda_iterative_ols))
+
+skipline(2)
+
+// Define a structure describing the parameters to be estimated (with initial conditions).
+clear eparams
+eparams.e_c_m   =  .9;
+eparams.c_z_1   =  .5;
+eparams.c_z_2   =  .2;
+eparams.c_z_dx2 =  .5;
+eparams.lambda  =  .7;
+
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2005Q1+4000, 'fmincon');
+
+e_c_m_nls = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_nls = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_nls = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+c_z_dx2_nls = M_.params(strmatch('c_z_dx2', M_.param_names, 'exact'));
+lambda_nls = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_nls))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_nls))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_nls))
+disp(sprintf('Estimate of c_z_dx2: %f', c_z_dx2_nls))
+disp(sprintf('Estimate of lambda: %f', lambda_nls))
+
+if abs(e_c_m_nls-e_c_m_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (e_c_m)')
+end
+
+if abs(c_z_1_nls-c_z_1_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_1)')
+end
+
+if abs(c_z_2_nls-c_z_2_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_2)')
+end
+
+if abs(c_z_dx2_nls-c_z_dx2_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_dx2)')
+end
+
+if abs(lambda_nls-lambda_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (lambda)')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-24/clean b/tests/pac/trend-component-24/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-24/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-24/example.mod b/tests/pac/trend-component-24/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..e3ff87b5fb67fea5e2d6b5ef9a024406dee535a0
--- /dev/null
+++ b/tests/pac/trend-component-24/example.mod
@@ -0,0 +1,155 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x u;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex eu;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*( y + x) + c_z_dx2*diff(x2) + c_z_u*u + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var ex = 0.1;
+    var eu = 0.05;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 5000);
+
+// Define a structure describing the parameters to be estimated (with initial conditions).
+clear eparams
+eparams.e_c_m   =  .9;
+eparams.c_z_1   =  .5;
+eparams.c_z_2   =  .2;
+eparams.lambda  =  .7;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2005Q1+4000);
+
+e_c_m_iterative_ols = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_iterative_ols = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_iterative_ols = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+lambda_iterative_ols = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_iterative_ols))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_iterative_ols))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_iterative_ols))
+disp(sprintf('Estimate of lambda: %f', lambda_iterative_ols))
+
+skipline(2)
+
+// Define a structure describing the parameters to be estimated (with initial conditions).
+clear eparams
+eparams.e_c_m   =  .9;
+eparams.c_z_1   =  .5;
+eparams.c_z_2   =  .2;
+eparams.lambda  =  .7;
+
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2005Q1+4000, 'fmincon');
+
+e_c_m_nls = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_nls = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_nls = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+lambda_nls = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_nls))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_nls))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_nls))
+disp(sprintf('Estimate of lambda: %f', lambda_nls))
+
+if abs(e_c_m_nls-e_c_m_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (e_c_m)')
+end
+
+if abs(c_z_1_nls-c_z_1_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_1)')
+end
+
+if abs(c_z_2_nls-c_z_2_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_2)')
+end
+
+if abs(lambda_nls-lambda_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (lambda)')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-25/clean b/tests/pac/trend-component-25/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-25/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-25/example.mod b/tests/pac/trend-component-25/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..f6d174e749799ed418ae790469d64f37791ff684
--- /dev/null
+++ b/tests/pac/trend-component-25/example.mod
@@ -0,0 +1,185 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x u v s;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex eu ev es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:s']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( y + x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.1;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 5000);
+
+// Define a structure describing the parameters to be estimated (with initial conditions).
+clear eparams
+eparams.e_c_m   =  .9;
+eparams.c_z_1   =  .5;
+eparams.c_z_2   =  .2;
+eparams.c_z_s   =  .9;
+eparams.c_z_dx2 =  .1;
+eparams.lambda  =  .7;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2005Q1+4000);
+
+e_c_m_iterative_ols = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_iterative_ols = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_iterative_ols = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+c_z_s_iterative_ols = M_.params(strmatch('c_z_s', M_.param_names, 'exact'));
+c_z_dx2_iterative_ols = M_.params(strmatch('c_z_dx2', M_.param_names, 'exact'));
+lambda_iterative_ols = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_iterative_ols))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_iterative_ols))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_iterative_ols))
+disp(sprintf('Estimate of c_z_s: %f', c_z_s_iterative_ols))
+disp(sprintf('Estimate of c_z_dx2: %f', c_z_dx2_iterative_ols))
+disp(sprintf('Estimate of lambda: %f', lambda_iterative_ols))
+
+skipline(2)
+
+// Define a structure describing the parameters to be estimated (with initial conditions).
+clear eparams
+eparams.e_c_m   =  .9;
+eparams.c_z_1   =  .5;
+eparams.c_z_2   =  .2;
+eparams.c_z_s   =  .9;
+eparams.c_z_dx2 =  .1;
+eparams.lambda  =  .7;
+
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2005Q1+4000, 'fmincon');
+
+e_c_m_nls = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+c_z_1_nls = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+c_z_2_nls = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+c_z_s_nls = M_.params(strmatch('c_z_s', M_.param_names, 'exact'));
+c_z_dx2_nls = M_.params(strmatch('c_z_dx2', M_.param_names, 'exact'));
+lambda_nls = M_.params(strmatch('lambda', M_.param_names, 'exact'));
+
+disp(sprintf('Estimate of e_c_m: %f', e_c_m_nls))
+disp(sprintf('Estimate of c_z_1: %f', c_z_1_nls))
+disp(sprintf('Estimate of c_z_2: %f', c_z_2_nls))
+disp(sprintf('Estimate of c_z_s: %f', c_z_s_nls))
+disp(sprintf('Estimate of c_z_dx2: %f', c_z_dx2_nls))
+disp(sprintf('Estimate of lambda: %f', lambda_nls))
+
+if abs(e_c_m_nls-e_c_m_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (e_c_m)')
+end
+
+if abs(c_z_1_nls-c_z_1_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_1)')
+end
+
+if abs(c_z_2_nls-c_z_2_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_2)')
+end
+
+if abs(c_z_s_nls-c_z_s_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_s)')
+end
+
+if abs(c_z_dx2_nls-c_z_dx2_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (c_z_dx2)')
+end
+
+if abs(lambda_nls-lambda_iterative_ols)>.01
+   error('Iterative OLS and NLS do not provide consistent estimates (lambda)')
+end
diff --git a/tests/pac/trend-component-26/clean b/tests/pac/trend-component-26/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-26/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-26/example.mod b/tests/pac/trend-component-26/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..e88b118993dd02b9497d91602b2deeac2eb3e75c
--- /dev/null
+++ b/tests/pac/trend-component-26/example.mod
@@ -0,0 +1,142 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x u v s;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey ex eu ev es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s cx cy beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+cx = 1.0;
+cy = 1.0;
+
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:s']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( cy*y + cx*x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.1;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Exogenous variables with non zero mean:
+pac.bgp.set('pacman', 'zpac', 'c_z_s', true);
+pac.bgp.set('pacman', 'zpac', 'cx', true);
+pac.bgp.set('pacman', 'zpac', 'c_z_dx2', true);
+
+id = find(strcmp('c_z_s', M_.param_names));
+id = find(id==M_.pac.pacman.equations.eq0.additive.params);
+if ~pac.bgp.get('pacman', 'zpac', 'additive', id)
+   error('bgp field in additive is wrong.')
+end
+
+id = find(strcmp('c_z_dv', M_.param_names));
+id = find(id==M_.pac.pacman.equations.eq0.additive.params);
+if pac.bgp.get('pacman', 'zpac', 'additive', id)
+   error('bgp field in additive is wrong.')
+end
+
+id = find(strcmp('cx', M_.param_names));
+id = find(id==M_.pac.pacman.equations.eq0.non_optimizing_behaviour.params);
+if ~pac.bgp.get('pacman', 'zpac', 'non_optimizing_behaviour', id)
+   error('bgp field in non_optimizing_behaviour is wrong.')
+end
+
+id = find(strcmp('cy', M_.param_names));
+id = find(id==M_.pac.pacman.equations.eq0.non_optimizing_behaviour.params);
+if pac.bgp.get('pacman', 'zpac', 'non_optimizing_behaviour', id)
+   error('bgp field in non_optimizing_behaviour is wrong.')
+end
+
+id = find(strcmp('c_z_dx2', M_.param_names));
+id = find(id==M_.pac.pacman.equations.eq0.optim_additive.params);
+if ~pac.bgp.get('pacman', 'zpac', 'optim_additive', id)
+   error('bgp field in optim_additive is wrong.')
+end
+
+id = find(strcmp('c_z_u', M_.param_names));
+id = find(id==M_.pac.pacman.equations.eq0.additive.params);
+if pac.bgp.get('pacman', 'zpac', 'optim_additive', id)
+   error('bgp field in optim_additive is wrong.')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-27/.gitignore b/tests/pac/trend-component-27/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..734fae6c56bbe1ca738e62b56f344ca1b950dd07
--- /dev/null
+++ b/tests/pac/trend-component-27/.gitignore
@@ -0,0 +1 @@
+simulation-files/*
diff --git a/tests/pac/trend-component-27/clean b/tests/pac/trend-component-27/clean
new file mode 100755
index 0000000000000000000000000000000000000000..cf3492a2882bd7f04ed0112d888b5031b10016c9
--- /dev/null
+++ b/tests/pac/trend-component-27/clean
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-27/example.mod b/tests/pac/trend-component-27/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..269d12e1dae02d9b0e8743a5e747095681636601
--- /dev/null
+++ b/tests/pac/trend-component-27/example.mod
@@ -0,0 +1,115 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x u v s;
+
+varexo ex1
+       ex2
+       ex1bar (used='estimationonly')
+       ex2bar (used='estimationonly')
+       ez
+       ey
+       ex
+       eu
+       ev
+       es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s cx cy beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+cx = 1.0;
+cy = 1.0;
+
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:s']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( cy*y + cx*x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.1;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Select a subset of the equations and print the equations, the list of parameters, endogenous
+// variables and exogenous variables in .inc files under ./simulation-files folder. Note that
+// innovations ex1bar and ex2bar will not appear in the equations.
+cherrypick('example', 'simulation-files', {'zpac', 'eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'}, true);
\ No newline at end of file
diff --git a/tests/pac/trend-component-28/clean b/tests/pac/trend-component-28/clean
new file mode 100755
index 0000000000000000000000000000000000000000..b70590094596c78121f704a245dd0758cc677c45
--- /dev/null
+++ b/tests/pac/trend-component-28/clean
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
+rm -f *.log
+
+rm -rf example1
+rm  -rf +example1
+
+rm -rf example2
+rm  -rf +example2
+
+rm -rf example3
+rm  -rf +example3
+
+rm -rf example4
+rm  -rf +example4
+
+rm -rf example5
+rm  -rf +example5
+
+rm -rf example6
+rm  -rf +example6
+
+
+
diff --git a/tests/pac/trend-component-28/example1.mod b/tests/pac/trend-component-28/example1.mod
new file mode 100644
index 0000000000000000000000000000000000000000..d42c87c6f694ed283b3ca3197182aa66f35ac0c6
--- /dev/null
+++ b/tests/pac/trend-component-28/example1.mod
@@ -0,0 +1,148 @@
+// --+ options: json=compute, stochastic +--
+
+PLOTS = true;
+
+var x1 x2 x3 x1bar x2bar z y x u v s;
+
+varexo ex1
+       ex2
+       ex1bar (used='estimationonly')
+       ex2bar (used='estimationonly')
+       ez
+       ey
+       ex
+       eu
+       ev
+       es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s cx cy beta
+       lambda
+       px3;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+cx = 1.0;
+cy = 1.0;
+
+
+lambda = 0.5; // Share of optimizing agents.
+
+px3 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:s']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x3']
+x3 = px3*x + y ;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( cy*y + cx*x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.1;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero for non logged variables, and one for logged variables
+init = zeros(10, M_.endo_nbr+M_.exo_nbr);
+initialconditions = dseries(init, 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
+TrueData_ = copy(TrueData);
+
+TrueData = equation.evaluate(TrueData, 'eq:x3', 2004Q1);
+
+if PLOTS
+
+    figure(1)
+    plot(TrueData_.x.data(12:end), TrueData_.x3.data(12:end)-TrueData.x3.data(12:end), '.k', 'linewidth', 2);
+
+    figure(2)
+    plot(TrueData_.x.data(12:end), '-k', 'linewidth', 2);
+
+    figure(3)
+    plot([TrueData_.x3.data(12:end)-TrueData.x3.data(12:end)], '-k', 'linewidth', 2);
+
+end
+
+
+fprintf('Max. abs. error is %s.\n', num2str(max(abs(TrueData.x3.data(12:end)-TrueData_.x3.data(12:end))), 16));
+
+if max(abs(TrueData.x3.data(12:end)-TrueData_.x3.data(12:end)))>1e-12
+   error('equation.evaluate() returned wrong values.')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-28/example2.mod b/tests/pac/trend-component-28/example2.mod
new file mode 100644
index 0000000000000000000000000000000000000000..9034fb10fa47ea230688365b4b53025076852669
--- /dev/null
+++ b/tests/pac/trend-component-28/example2.mod
@@ -0,0 +1,147 @@
+// --+ options: json=compute, stochastic +--
+
+PLOTS = true;
+
+var x1 x2 x3 x1bar x2bar z y x u v s;
+
+varexo ex1
+       ex2
+       ex1bar (used='estimationonly')
+       ex2bar (used='estimationonly')
+       ez
+       ey
+       ex
+       eu
+       ev
+       es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s cx cy beta
+       lambda
+       px3;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+cx = 1.0;
+cy = 1.0;
+
+
+lambda = 0.5; // Share of optimizing agents.
+
+px3 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:s']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x3']
+log(x3) = x ;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( cy*y + cx*x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.1;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero for non logged variables, and one for logged variables
+init = rand(10, M_.endo_nbr+M_.exo_nbr);
+initialconditions = dseries(init, 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
+TrueData_ = copy(TrueData);
+
+TrueData = equation.evaluate(TrueData, 'eq:x3', 2004Q1);
+
+if PLOTS
+
+    figure(1)
+    plot(TrueData_.x.data(12:end), TrueData_.x3.data(12:end)-TrueData.x3.data(12:end), '.k', 'linewidth', 2);
+
+    figure(2)
+    plot(TrueData_.x.data(12:end), '-k', 'linewidth', 2);
+
+    figure(3)
+    plot([TrueData_.x3.data(12:end)-TrueData.x3.data(12:end)], '-k', 'linewidth', 2);
+
+end
+
+fprintf('Max. abs. error is %s.\n', num2str(max(abs(TrueData.x3.data(12:end)-TrueData_.x3.data(12:end))), 16));
+
+if max(abs(TrueData.x3.data(12:end)-TrueData_.x3.data(12:end)))>1e-5
+   error('equation.evaluate() returned wrong values.')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-28/example3.mod b/tests/pac/trend-component-28/example3.mod
new file mode 100644
index 0000000000000000000000000000000000000000..9a74a10b8bbc9ba21ed4f69e9e81e8ec34b7d631
--- /dev/null
+++ b/tests/pac/trend-component-28/example3.mod
@@ -0,0 +1,147 @@
+// --+ options: json=compute, stochastic +--
+
+PLOTS = true;
+
+var x1 x2 x3 x1bar x2bar z y x u v s;
+
+varexo ex1
+       ex2
+       ex1bar (used='estimationonly')
+       ex2bar (used='estimationonly')
+       ez
+       ey
+       ex
+       eu
+       ev
+       es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s cx cy beta
+       lambda
+       px3;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+cx = 1.0;
+cy = 1.0;
+
+
+lambda = 0.5; // Share of optimizing agents.
+
+px3 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:s']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x3']
+diff(x3) = x ;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( cy*y + cx*x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.1;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero for non logged variables, and one for logged variables
+init = randn(10, M_.endo_nbr+M_.exo_nbr);
+initialconditions = dseries(init, 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
+TrueData_ = copy(TrueData);
+
+TrueData = equation.evaluate(TrueData, 'eq:x3', 2004Q1);
+
+if PLOTS
+
+    figure(1)
+    plot(TrueData_.x.data(12:end), TrueData_.x3.data(12:end)-TrueData.x3.data(12:end), '.k', 'linewidth', 2);
+
+    figure(2)
+    plot(TrueData_.x.data(12:end), '-k', 'linewidth', 2);
+
+    figure(3)
+    plot([TrueData_.x3.data(12:end)-TrueData.x3.data(12:end)], '-k', 'linewidth', 2);
+
+end
+
+fprintf('Max. abs. error is %s.\n', num2str(max(abs(TrueData.x3.data(12:end)-TrueData_.x3.data(12:end))), 16));
+
+if max(abs(TrueData.x3.data(12:end)-TrueData_.x3.data(12:end)))>1e-12
+   error('equation.evaluate() returned wrong values.')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-28/example4.mod b/tests/pac/trend-component-28/example4.mod
new file mode 100644
index 0000000000000000000000000000000000000000..5fced3966518c05fd9518a424c9c06167829f69a
--- /dev/null
+++ b/tests/pac/trend-component-28/example4.mod
@@ -0,0 +1,148 @@
+// --+ options: json=compute, stochastic +--
+
+PLOTS = true;
+
+var x1 x2 x3 x1bar x2bar z y x u v s;
+
+varexo ex1
+       ex2
+       ex1bar (used='estimationonly')
+       ex2bar (used='estimationonly')
+       ez
+       ey
+       ex
+       eu
+       ev
+       es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s cx cy beta
+       lambda
+       px3;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+cx = 1.0;
+cy = 1.0;
+
+
+lambda = 0.5; // Share of optimizing agents.
+
+px3 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:s']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x3']
+diff(log(x3)) = x ;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( cy*y + cx*x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.01;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero for non logged variables, and one for logged variables
+init = ones(10, M_.endo_nbr+M_.exo_nbr);
+initialconditions = dseries(init, 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+options_.solve_tolf = 1e-9;
+TrueData = simul_backward_model(initialconditions, 5000);
+TrueData_ = copy(TrueData);
+
+TrueData = equation.evaluate(TrueData, 'eq:x3', 2004Q1);
+
+if PLOTS
+
+    figure(1)
+    plot(TrueData_.x.data(12:end), TrueData_.x3.data(12:end)-TrueData.x3.data(12:end), '.k', 'linewidth', 2);
+
+    figure(2)
+    plot(TrueData_.x.data(12:end), '-k', 'linewidth', 2);
+
+    figure(3)
+    plot([TrueData_.x3.data(12:end)-TrueData.x3.data(12:end)], '-k', 'linewidth', 2);
+
+end
+
+fprintf('Max. abs. error is %s.\n', num2str(max(abs(TrueData.x3.data(12:end)-TrueData_.x3.data(12:end))), 16));
+
+if max(abs(TrueData.x3.data(12:end)-TrueData_.x3.data(12:end)))>1e-5
+   error('equation.evaluate() returned wrong values.')
+end
diff --git a/tests/pac/trend-component-28/example5.mod b/tests/pac/trend-component-28/example5.mod
new file mode 100644
index 0000000000000000000000000000000000000000..e7226aab4f23452edf478fa013827bb150658f85
--- /dev/null
+++ b/tests/pac/trend-component-28/example5.mod
@@ -0,0 +1,147 @@
+// --+ options: json=compute, stochastic +--
+
+PLOTS = true;
+
+var x1 x2 x3 x1bar x2bar z y x u v s;
+
+varexo ex1
+       ex2
+       ex1bar (used='estimationonly')
+       ex2bar (used='estimationonly')
+       ez
+       ey
+       ex
+       eu
+       ev
+       es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s cx cy beta
+       lambda
+       px3;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+cx = 1.0;
+cy = 1.0;
+
+
+lambda = 0.5; // Share of optimizing agents.
+
+px3 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:s']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x3']
+diff(diff(x3)) = x ;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( cy*y + cx*x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.01;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero for non logged variables, and one for logged variables
+init = ones(10, M_.endo_nbr+M_.exo_nbr);
+initialconditions = dseries(init, 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
+TrueData_ = copy(TrueData);
+
+TrueData = equation.evaluate(TrueData, 'eq:x3', 2004Q1);
+
+if PLOTS
+
+    figure(1)
+    plot(TrueData_.x.data(12:end), TrueData_.x3.data(12:end)-TrueData.x3.data(12:end), '.k', 'linewidth', 2);
+
+    figure(2)
+    plot(TrueData_.x.data(12:end), '-k', 'linewidth', 2);
+
+    figure(3)
+    plot([TrueData_.x3.data(12:end)-TrueData.x3.data(12:end)], '-k', 'linewidth', 2);
+
+end
+
+fprintf('Max. abs. error is %s.\n', num2str(max(abs(TrueData.x3.data(12:end)-TrueData_.x3.data(12:end))), 16));
+
+if max(abs(TrueData.x3.data(12:end)-TrueData_.x3.data(12:end)))>1e-12
+   error('equation.evaluate() returned wrong values.')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-28/example6.mod b/tests/pac/trend-component-28/example6.mod
new file mode 100644
index 0000000000000000000000000000000000000000..19e64c55a160fb19eeb47591911a4120e3d07483
--- /dev/null
+++ b/tests/pac/trend-component-28/example6.mod
@@ -0,0 +1,147 @@
+// --+ options: json=compute, stochastic +--
+
+PLOTS = true;
+
+var x1 x2 x3 x1bar x2bar z y x u v s;
+
+varexo ex1
+       ex2
+       ex1bar (used='estimationonly')
+       ex2bar (used='estimationonly')
+       ez
+       ey
+       ex
+       eu
+       ev
+       es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s cx cy beta
+       lambda
+       px3;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+cx = 1.0;
+cy = 1.0;
+
+
+lambda = 0.5; // Share of optimizing agents.
+
+px3 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:s']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x3']
+diff(diff(log(x3))) = x ;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( cy*y + cx*x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.01;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero for non logged variables, and one for logged variables
+init = ones(10, M_.endo_nbr+M_.exo_nbr);
+initialconditions = dseries(init, 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 50);
+TrueData_ = copy(TrueData);
+
+TrueData = equation.evaluate(TrueData, 'eq:x3', 2004Q1);
+
+if PLOTS
+
+    figure(1)
+    plot(TrueData_.x.data(12:end), TrueData_.x3.data(12:end)-TrueData.x3.data(12:end), '.k', 'linewidth', 2);
+
+    figure(2)
+    plot(TrueData_.x.data(12:end), '-k', 'linewidth', 2);
+
+    figure(3)
+    plot([TrueData_.x3.data(12:end)-TrueData.x3.data(12:end)], '-k', 'linewidth', 2);
+
+end
+
+fprintf('Max. abs. error is %s.\n', num2str(max(abs(TrueData.x3.data(12:end)-TrueData_.x3.data(12:end))), 16));
+
+if max(abs(TrueData.x3.data(12:end)-TrueData_.x3.data(12:end)))>1e-5
+   error('equation.evaluate() returned wrong values.')
+end
\ No newline at end of file
diff --git a/tests/pac/trend-component-29/.gitignore b/tests/pac/trend-component-29/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..a313cff7e3e6f714a4319de4af93e10a46144b26
--- /dev/null
+++ b/tests/pac/trend-component-29/.gitignore
@@ -0,0 +1,2 @@
+simulation-files1/*
+simulation-files2/*
diff --git a/tests/pac/trend-component-29/clean b/tests/pac/trend-component-29/clean
new file mode 100755
index 0000000000000000000000000000000000000000..eac96faeedba5106cf13ea7205ed26d3a2bc1a74
--- /dev/null
+++ b/tests/pac/trend-component-29/clean
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+rm -rf example1
+rm  -rf +example1
+rm -f example1.log
+
+rm -rf simulation-files1
+
+rm -rf example2
+rm  -rf +example2
+rm -f example2.log
+
+rm -rf simulation-files2
+
+rm -f *.mat
+rm -f *.m
+rm -f *.dat
diff --git a/tests/pac/trend-component-29/example1.mod b/tests/pac/trend-component-29/example1.mod
new file mode 100644
index 0000000000000000000000000000000000000000..8870d7afa24cc5188b7f16ff989ac4fc4f656ac1
--- /dev/null
+++ b/tests/pac/trend-component-29/example1.mod
@@ -0,0 +1,118 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x u v s azertyuiopiop;
+
+varexo ex1
+       ex2
+       ex1bar (used='estimationonly')
+       ex2bar (used='estimationonly')
+       ez
+       ey
+       ex
+       eu
+       ev
+       es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s cx cy beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+cx = 1.0;
+cy = 1.0;
+
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:s']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:azertyuiopiop', rename='azertyuiopiop->qsdfghjklm']
+azertyuiopiop = x + y;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( cy*y + cx*x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.1;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Select a subset of the equations and print the equations, the list of parameters, endogenous
+// variables and exogenous variables in .inc files under ./simulation-files folder. Note that
+// innovations ex1bar and ex2bar will not appear in the equations.
+cherrypick('example1', 'simulation-files1', {'zpac', 'eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar', 'eq:azertyuiopiop'}, true);
\ No newline at end of file
diff --git a/tests/pac/trend-component-29/example2.mod b/tests/pac/trend-component-29/example2.mod
new file mode 100644
index 0000000000000000000000000000000000000000..6a9a6c5c723b06a710ee1b17544e0b054d7fedf5
--- /dev/null
+++ b/tests/pac/trend-component-29/example2.mod
@@ -0,0 +1,115 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x u v s;
+
+varexo ex1
+       ex2
+       ex1bar (used='estimationonly')
+       ex2bar (used='estimationonly')
+       ez
+       ey
+       ex
+       eu
+       ev
+       es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s cx cy beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+cx = 1.0;
+cy = 1.0;
+
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:s']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1', rename='x1->x3']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( cy*y + cx*x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.1;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Select a subset of the equations and print the equations, the list of parameters, endogenous
+// variables and exogenous variables in .inc files under ./simulation-files folder. Note that
+// innovations ex1bar and ex2bar will not appear in the equations.
+cherrypick('example2', 'simulation-files2', {'zpac', 'eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'}, true);
\ No newline at end of file
diff --git a/tests/pac/trend-component-3/clean b/tests/pac/trend-component-3/clean
new file mode 100755
index 0000000000000000000000000000000000000000..2935a38ad605cee3810c18217e54906355524374
--- /dev/null
+++ b/tests/pac/trend-component-3/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example*.mat
+rm -f example.log
\ No newline at end of file
diff --git a/tests/pac/trend-component-3/example.mod b/tests/pac/trend-component-3/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..137813d614ae3cc08c4a9a1980d9688e966aff85
--- /dev/null
+++ b/tests/pac/trend-component-3/example.mod
@@ -0,0 +1,75 @@
+// --+ options: json=compute, transform_unary_ops, stochastic +--
+
+var x1 x2 x1bar x2bar z ;
+
+varexo ex1 ex2 ex1bar ex2bar ez ;
+
+parameters a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta ;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .1;
+e_c_m =  .1;
+c_z_1 =  .07;
+c_z_2 = -.3;
+
+gamma =  .7;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar',  'eq:x2bar'], targets=['eq:x1bar',  'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:x1']
+diff(diff(x1)) = a_x1_0*(diff(x1(-1))-diff(x1bar(-1))) + a_x1_1*diff(diff(x1(-1))) + a_x1_2*diff(diff(x1(-2))) + a_x1_x2_1*diff(log(x2(-1))) + a_x1_x2_2*diff(log(x2(-2))) + ex1;     
+
+[name='eq:x2']
+diff(log(x2)) = a_x2_0*(log(x2(-1))-log(x2bar(-1))) + a_x2_1*diff(diff(x1(-1))) + a_x2_2*diff(diff(x1(-2))) + a_x2_x1_1*diff(log(x2(-1))) + a_x2_x1_2*diff(log(x2(-2))) + ex2;     
+
+[name='eq:x1bar']
+diff(x1bar) = diff(x1bar(-1)) + ex1bar;
+
+[name='eq:x2bar']
+log(x2bar) = log(x2bar(-1)) + ex2bar;
+
+[name='eq:pac']
+diff(z) = gamma*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-gamma)*ez;
+
+
+end;
+
+shocks;
+    var ex1 = 1;
+    var ex2 = 1;
+    var ex1bar = 1;
+    var ex2bar = 1;
+    var ez = 1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero for non logged variables, and one for logged variables
+init = zeros(10, M_.endo_nbr+M_.exo_nbr);
+init(:,[2,4]) = ones(10,2);
+initialconditions = dseries(init, 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
diff --git a/tests/pac/trend-component-30/clean b/tests/pac/trend-component-30/clean
new file mode 100755
index 0000000000000000000000000000000000000000..be0d5e00cdb49fa48f99aa6470ff0578973bbce3
--- /dev/null
+++ b/tests/pac/trend-component-30/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm -rf +example
+rm -f example*.mat
+rm -f example.log
\ No newline at end of file
diff --git a/tests/pac/trend-component-30/example.mod b/tests/pac/trend-component-30/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..9b15cf3d87c1650867ff2069e7ed29df9c0899a3
--- /dev/null
+++ b/tests/pac/trend-component-30/example.mod
@@ -0,0 +1,72 @@
+// --+ options: json=compute, stochastic +--
+
+// Test with two PAC equations in the same file
+
+var x1 x2 x1bar x2bar z u;
+
+varexo ex1 ex2 ex1bar ex2bar ez eu;
+
+parameters a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m_z e_c_m_u c_z_1 c_z_2 c_u_1 c_u_2 gamma_z gamma_u beta ;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m_z =  .5;
+e_c_m_u =  .6;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_u_1 =  .2;
+c_u_2 = -.1;
+gamma_z =  .7;
+gamma_u =  .8;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=nowhereman);
+
+model;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='eq:pac:z']
+diff(z) = gamma_z*(e_c_m_z*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-gamma_z)*ez;
+
+[name='eq:pac:u']
+diff(u) = gamma_u*(e_c_m_u*(x2(-1)-u(-1)) + c_u_1*diff(u(-1))  + c_u_2*diff(u(-2)) + pac_expectation(nowhereman)) + (1-gamma_u)*eu;
+
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var eu = 1.0;
+end;
diff --git a/tests/pac/trend-component-31/clean b/tests/pac/trend-component-31/clean
new file mode 100755
index 0000000000000000000000000000000000000000..be0d5e00cdb49fa48f99aa6470ff0578973bbce3
--- /dev/null
+++ b/tests/pac/trend-component-31/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm -rf +example
+rm -f example*.mat
+rm -f example.log
\ No newline at end of file
diff --git a/tests/pac/trend-component-31/example.mod b/tests/pac/trend-component-31/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..f537cb226771e9d615bec9adcbae7b082e23d367
--- /dev/null
+++ b/tests/pac/trend-component-31/example.mod
@@ -0,0 +1,74 @@
+// --+ options: json=compute, stochastic +--
+
+// Regression test for bug preprocessor#52
+
+var x1 x2 x1bar x2bar z ;
+
+varexo ex1 ex2 ex1bar ex2bar ez ;
+
+parameters a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta ;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+gamma =  .7;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='eq:pac']
+diff(z) = gamma*(e_c_m*(x1(-1)-z(-1)) + pac_expectation(pacman)) + (1-gamma)*ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
diff --git a/tests/pac/trend-component-4/clean b/tests/pac/trend-component-4/clean
new file mode 100755
index 0000000000000000000000000000000000000000..2935a38ad605cee3810c18217e54906355524374
--- /dev/null
+++ b/tests/pac/trend-component-4/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example*.mat
+rm -f example.log
\ No newline at end of file
diff --git a/tests/pac/trend-component-4/example.mod b/tests/pac/trend-component-4/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..b4cb9eb66a547728560ff084f5bd7d07bfd72d0e
--- /dev/null
+++ b/tests/pac/trend-component-4/example.mod
@@ -0,0 +1,73 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z ;
+
+varexo ex1 ex2 ex1bar ex2bar ez ;
+
+parameters a_x1_0 a_x1_0_ a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta ;
+
+a_x1_0 =  -.9;
+a_x1_0_ =  -.8;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+gamma =  .9;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1))+a_x1_0_*(x2(-1)-x2bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='eq:pac']
+diff(z) = gamma*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-gamma)*ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 5000);
\ No newline at end of file
diff --git a/tests/pac/trend-component-5/clean b/tests/pac/trend-component-5/clean
new file mode 100755
index 0000000000000000000000000000000000000000..2935a38ad605cee3810c18217e54906355524374
--- /dev/null
+++ b/tests/pac/trend-component-5/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example*.mat
+rm -f example.log
\ No newline at end of file
diff --git a/tests/pac/trend-component-5/example.mod b/tests/pac/trend-component-5/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..afc28b482ed41c5ff9bb4bad41cd8428d30773b6
--- /dev/null
+++ b/tests/pac/trend-component-5/example.mod
@@ -0,0 +1,82 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta ;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+gamma =  .7;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='eq:pac']
+diff(z) = gamma*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-gamma)*y + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
+
diff --git a/tests/pac/trend-component-6/clean b/tests/pac/trend-component-6/clean
new file mode 100755
index 0000000000000000000000000000000000000000..0d64aefdef6d2368cc070b20e575ca5e6ce127f4
--- /dev/null
+++ b/tests/pac/trend-component-6/clean
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm *.m
diff --git a/tests/pac/trend-component-6/example.mod b/tests/pac/trend-component-6/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..c4cc3228bd52364944c9bee8dfb9e81bffb4240f
--- /dev/null
+++ b/tests/pac/trend-component-6/example.mod
@@ -0,0 +1,101 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta ;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+gamma =  .7;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = gamma*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-gamma)*y + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
+
+//[pnames, enames, xnames, pid, eid, xid] = get_variables_and_parameters_in_equation('zpac', M_)
+
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m = .9;
+eparams.c_z_1 = .5;
+eparams.c_z_2 = .2;
+eparams.gamma = .1;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 200Q1, 'ez');
+
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2120Q1);
+
+disp(sprintf('Estimate of e_c_m: %f', M_.params(strmatch('e_c_m', M_.param_names, 'exact'))))
+disp(sprintf('Estimate of c_z_1: %f', M_.params(strmatch('c_z_1', M_.param_names, 'exact'))))
+disp(sprintf('Estimate of c_z_2: %f', M_.params(strmatch('c_z_2', M_.param_names, 'exact'))))
+disp(sprintf('Estimate of gamma: %f', M_.params(strmatch('gamma', M_.param_names, 'exact'))))
diff --git a/tests/pac/trend-component-7/clean b/tests/pac/trend-component-7/clean
new file mode 100755
index 0000000000000000000000000000000000000000..6f2442c33a30d840d93824c6a73ea4329314c774
--- /dev/null
+++ b/tests/pac/trend-component-7/clean
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+rm -rf example
+rm -rf +example
+rm -f example*.mat
+rm -f example.log
+rm -f *.m
\ No newline at end of file
diff --git a/tests/pac/trend-component-7/example.mod b/tests/pac/trend-component-7/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..64f48146e16918345fc4eaaa5840e50c381ab624
--- /dev/null
+++ b/tests/pac/trend-component-7/example.mod
@@ -0,0 +1,97 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 gamma beta ;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
+
+//[pnames, enames, xnames, pid, eid, xid] = get_variables_and_parameters_in_equation('zpac', M_)
+
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m = .9;
+eparams.c_z_1 = .5;
+eparams.c_z_2 = .2;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 200Q1, 'ez');
+
+pac.estimate.nls('zpac', eparams, edata, 2005Q1:2120Q1);
+
+disp(sprintf('Estimate of e_c_m: %f', M_.params(strmatch('e_c_m', M_.param_names, 'exact'))))
+disp(sprintf('Estimate of c_z_1: %f', M_.params(strmatch('c_z_1', M_.param_names, 'exact'))))
+disp(sprintf('Estimate of c_z_2: %f', M_.params(strmatch('c_z_2', M_.param_names, 'exact'))))
diff --git a/tests/pac/trend-component-8-mc-iterative-ols/clean b/tests/pac/trend-component-8-mc-iterative-ols/clean
new file mode 100755
index 0000000000000000000000000000000000000000..bdc7da19ab956a4a155e5fc8cbdf9a11ebbebff0
--- /dev/null
+++ b/tests/pac/trend-component-8-mc-iterative-ols/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
\ No newline at end of file
diff --git a/tests/pac/trend-component-8-mc-iterative-ols/example.mod b/tests/pac/trend-component-8-mc-iterative-ols/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..c5be0854e140122ccda80e9d33a5c5007c9d9c4f
--- /dev/null
+++ b/tests/pac/trend-component-8-mc-iterative-ols/example.mod
@@ -0,0 +1,106 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta g;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+g=.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, growth=g, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+B = 1;
+X = zeros(3,B);
+
+set_dynare_seed('default');
+options_.bnlms.set_dynare_seed_to_default = false;
+
+for i=1:B
+    e_c_m =  .5;
+    c_z_1 =  .2;
+    c_z_2 = -.1;
+    // Simulate the model for 500 periods
+    TrueData = simul_backward_model(initialconditions, 300);
+    // Define a structure describing the parameters to be estimated (with initial conditions). 
+    clear eparams
+    eparams.e_c_m = -.5;
+    eparams.c_z_1 = .2;
+    eparams.c_z_2 =-.1;
+    // Define the dataset used for estimation
+    edata = TrueData;
+    edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+    pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2000Q1+200);
+    X(1,i) = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+    X(2,i) = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+    X(3,i) = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+end
+
+mean(X, 2)
diff --git a/tests/pac/trend-component-8-mc-nls/clean b/tests/pac/trend-component-8-mc-nls/clean
new file mode 100755
index 0000000000000000000000000000000000000000..0d64aefdef6d2368cc070b20e575ca5e6ce127f4
--- /dev/null
+++ b/tests/pac/trend-component-8-mc-nls/clean
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
+rm *.m
diff --git a/tests/pac/trend-component-8-mc-nls/example.mod b/tests/pac/trend-component-8-mc-nls/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..e9dbdbd6cb7b11af7ece738a1a03cb8b77409f1b
--- /dev/null
+++ b/tests/pac/trend-component-8-mc-nls/example.mod
@@ -0,0 +1,102 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta g;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+g = .1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, growth=g, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+B = 1;
+X = zeros(3,B);
+
+set_dynare_seed('default');
+options_.bnlms.set_dynare_seed_to_default = false;
+
+for i=1:B
+    // Simulate the model for 500 periods
+    TrueData = simul_backward_model(initialconditions, 300);
+    // Define a structure describing the parameters to be estimated (with initial conditions). 
+    clear eparams
+    eparas.e_c_m =  .5;
+    eparams.c_z_1 = .2;
+    eparams.c_z_2 =-.1;
+    // Define the dataset used for estimation
+    edata = TrueData;
+    edata.ez = dseries(NaN(TrueData.nobs, 1), 200Q1, 'ez');
+    pac.estimate.nls('zpac', eparams, edata, 2005Q1:2000Q1+200);
+    X(1,i) = M_.params(strmatch('e_c_m', M_.param_names, 'exact'));
+    X(2,i) = M_.params(strmatch('c_z_1', M_.param_names, 'exact'));
+    X(3,i) = M_.params(strmatch('c_z_2', M_.param_names, 'exact'));
+end
+
+mean(X, 2)
diff --git a/tests/pac/trend-component-9/clean b/tests/pac/trend-component-9/clean
new file mode 100755
index 0000000000000000000000000000000000000000..bdc7da19ab956a4a155e5fc8cbdf9a11ebbebff0
--- /dev/null
+++ b/tests/pac/trend-component-9/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm  -rf +example
+rm -f example.log
+rm -f *.mat
\ No newline at end of file
diff --git a/tests/pac/trend-component-9/example.mod b/tests/pac/trend-component-9/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..a9b0b3bb8cf18316f3638fcda8122ae21af28daf
--- /dev/null
+++ b/tests/pac/trend-component-9/example.mod
@@ -0,0 +1,93 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y;
+
+varexo ex1 ex2 ex1bar ex2bar ez ey;
+
+parameters
+       rho_1 rho_2
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta;
+
+rho_1 = .9;
+rho_2 = -.2;
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 300);
+
+// Define a structure describing the parameters to be estimated (with initial conditions). 
+clear eparams
+eparams.e_c_m =  .9;
+eparams.c_z_1 =  .5;
+eparams.c_z_2 =  .2;
+
+// Define the dataset used for estimation
+edata = TrueData;
+edata.ez = dseries(NaN(TrueData.nobs, 1), 2000Q1, 'ez');
+pac.estimate.iterative_ols('zpac', eparams, edata, 2005Q1:2000Q1+200);
+
+disp(sprintf('Estimate of e_c_m: %f', M_.params(strmatch('e_c_m', M_.param_names, 'exact'))))
+disp(sprintf('Estimate of c_z_1: %f', M_.params(strmatch('c_z_1', M_.param_names, 'exact'))))
+disp(sprintf('Estimate of c_z_2: %f', M_.params(strmatch('c_z_2', M_.param_names, 'exact'))))
diff --git a/tests/pac/var-0/clean b/tests/pac/var-0/clean
new file mode 100755
index 0000000000000000000000000000000000000000..e0d1cd114f175d1abb2dac42b71568fd53b95e3e
--- /dev/null
+++ b/tests/pac/var-0/clean
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+rm -rf m1 m2 m3 m4
+rm -f m1_dynamic.m  m1.log  m1.m  m1_results.mat  m1_set_auxiliary_variables.m  m1_static.m
+rm -f m2_dynamic.m  m2.log  m2.m  m2_results.mat  m2_set_auxiliary_variables.m  m2_static.m
+rm -f m3_dynamic.m  m3.log  m3.m  m3_results.mat  m3_set_auxiliary_variables.m  m3_static.m
+rm -f m4_dynamic.m  m4.log  m4.m  m4_results.mat  m4_set_auxiliary_variables.m  m4_static.m
diff --git a/tests/pac/var-0/m1.mod b/tests/pac/var-0/m1.mod
new file mode 100644
index 0000000000000000000000000000000000000000..7ebe59034c3733b66530342cb674f38bf9335a4b
--- /dev/null
+++ b/tests/pac/var-0/m1.mod
@@ -0,0 +1,30 @@
+var y x z;
+
+varexo ex ey ez;
+
+parameters a_y_1 a_y_2 b_y_1 b_y_2 b_x_1 b_x_2 c_z_1 d;
+
+a_y_1 =  .2;
+a_y_2 =  .3;
+b_y_1 =  .1;
+b_y_2 =  .4;
+b_x_1 = -.1;
+b_x_2 = -.2; 
+c_z_1 =  .9;
+d     =  .1;
+
+var_model(model_name=toto, eqtags=['eq:x', 'eq:y']);
+
+model;
+
+[name='eq:y']
+y = a_y_1*y(-1) + a_y_2*x(-1) + b_y_1*y(-2) + b_y_2*x(-2) + ey ;
+
+z = c_z_1*z(-3) + d*y + ez;
+
+[name='eq:x']
+x = b_x_1*y(-2) + b_x_2*x(-2) + ez ;
+
+end;
+
+get_companion_matrix('toto');
diff --git a/tests/pac/var-0/m2.mod b/tests/pac/var-0/m2.mod
new file mode 100644
index 0000000000000000000000000000000000000000..475a5203907e2b58cf2cd43670b68fc90e6a6f1b
--- /dev/null
+++ b/tests/pac/var-0/m2.mod
@@ -0,0 +1,30 @@
+var y x z;
+
+varexo ex ey ez;
+
+parameters a_y_1 a_y_2 b_y_1 b_y_2 b_x_1 b_x_2 c_z_1 d;
+
+a_y_1 =  .2;
+a_y_2 =  .3;
+b_y_1 =  .1;
+b_y_2 =  .4;
+b_x_1 = -.1;
+b_x_2 = -.2; 
+c_z_1 =  .9;
+d     =  .1;
+
+var_model(model_name=toto, eqtags=['eq:x', 'eq:y']);
+
+model;
+
+[name='eq:y']
+y = a_y_1*y(-1) + a_y_2*diff(x(-1)) + b_y_1*y(-2) + b_y_2*diff(x(-2)) + ey ;
+
+z = c_z_1*z(-3) + d*y + ez;
+
+[name='eq:x']
+diff(x) = b_x_1*y(-2) + b_x_2*diff(x(-1)) + ez ;
+
+end;
+
+get_companion_matrix('toto');
\ No newline at end of file
diff --git a/tests/pac/var-0/m3.mod b/tests/pac/var-0/m3.mod
new file mode 100644
index 0000000000000000000000000000000000000000..eaf79b78281c1ef4b651a182d87a0ef15e9acb0e
--- /dev/null
+++ b/tests/pac/var-0/m3.mod
@@ -0,0 +1,32 @@
+var y x z;
+
+varexo ex ey ez;
+
+parameters a_y_1 a_y_2 b_y_1 b_y_2 b_x_1 b_x_2 c_z_1 c_z_2 c_z_3;
+
+a_y_1 =  .2;
+a_y_2 =  .3;
+b_y_1 =  .1;
+b_y_2 =  .4;
+b_x_1 = -.1;
+b_x_2 = -.2; 
+c_z_1 =  .9;
+c_z_2 =  .1;
+c_z_3 = -.8;
+
+var_model(model_name=toto, eqtags=['eq:x', 'eq:y', 'eq:z']);
+
+model;
+
+[name='eq:y']
+y = a_y_1*y(-1) + a_y_2*diff(x(-1)) + b_y_1*y(-2) + b_y_2*diff(x(-2)) + ey ;
+
+[name='eq:x']
+diff(x) = b_x_1*y(-2) + b_x_2*diff(x(-1)) + ex ;
+
+[name='eq:z']
+diff(z) = c_z_1*(x(-1)-z(-1)) + c_z_2*diff(z(-1)) + c_z_3*diff(z(-2)) + ez ;
+
+end;
+
+get_ar_matrices('toto');
\ No newline at end of file
diff --git a/tests/pac/var-0/m4.mod b/tests/pac/var-0/m4.mod
new file mode 100644
index 0000000000000000000000000000000000000000..f92fc75ed553dac8671010c092313e52861f0b8b
--- /dev/null
+++ b/tests/pac/var-0/m4.mod
@@ -0,0 +1,29 @@
+var y x z;
+
+varexo ex ey ez;
+
+parameters a_x_0 a_x_1 a_x_2 b_z_0 b_z_1 b_z_2;
+
+a_x_0 =  .2;
+a_x_1 =  .9;
+a_x_2 = -.2;
+b_z_0 =  .3;
+b_z_1 =  .7;
+b_z_2 = -.4;
+
+var_model(model_name=toto, eqtags=['eq:x', 'eq:z', 'eq:y']);
+
+model;
+
+[name='eq:y']
+y = y(-1) + ey ;
+
+[name='eq:x']
+diff(x) = -a_x_0*(x(-1)-y(-1)) + a_x_1*diff(x(-1)) + a_x_2*diff(x(-2)) + ex ;
+
+[name='eq:z']
+diff(z) = -b_z_0*(z(-1)-x(-1)) + b_z_1*diff(z(-1)) + b_z_2*diff(z(-2)) + ez ;
+
+end;
+
+get_ar_matrices('toto');
\ No newline at end of file
diff --git a/tests/pac/var-1/clean b/tests/pac/var-1/clean
new file mode 100755
index 0000000000000000000000000000000000000000..be0d5e00cdb49fa48f99aa6470ff0578973bbce3
--- /dev/null
+++ b/tests/pac/var-1/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm -rf +example
+rm -f example*.mat
+rm -f example.log
\ No newline at end of file
diff --git a/tests/pac/var-1/example.mod b/tests/pac/var-1/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..1af81481dde400afd4fc7156b81cff818a657970
--- /dev/null
+++ b/tests/pac/var-1/example.mod
@@ -0,0 +1,56 @@
+// --+ options: json=compute, stochastic +--
+
+var y x z;
+
+varexo ex ey ez;
+
+parameters a_y_1 a_y_2 b_y_1 b_y_2 b_x_1 b_x_2 ; // VAR parameters
+
+parameters beta e_c_m c_z_1 c_z_2;               // PAC equation parameters
+
+a_y_1 =  .2;
+a_y_2 =  .3;
+b_y_1 =  .1;
+b_y_2 =  .4;
+b_x_1 = -.1;
+b_x_2 = -.2;
+
+beta  =  .9;
+e_c_m =  .1;
+c_z_1 =  .7;
+c_z_2 = -.3;
+
+var_model(model_name=toto, eqtags=['eq:x', 'eq:y']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = a_y_1*y(-1) + a_y_2*diff(x(-1)) + b_y_1*y(-2) + b_y_2*diff(x(-2)) + ey ;
+
+[name='eq:x']
+diff(x) = b_x_1*y(-2) + b_x_2*diff(x(-1)) + ex ;
+
+[name='eq:pac']
+diff(z) = e_c_m*(x(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex = 1.0;
+    var ey = 1.0;
+    var ez = 1.0;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
\ No newline at end of file
diff --git a/tests/pac/var-2/clean b/tests/pac/var-2/clean
new file mode 100755
index 0000000000000000000000000000000000000000..be0d5e00cdb49fa48f99aa6470ff0578973bbce3
--- /dev/null
+++ b/tests/pac/var-2/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm -rf +example
+rm -f example*.mat
+rm -f example.log
\ No newline at end of file
diff --git a/tests/pac/var-2/example.mod b/tests/pac/var-2/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..8c212f26639765ac1c8d71f33167ceb939632138
--- /dev/null
+++ b/tests/pac/var-2/example.mod
@@ -0,0 +1,58 @@
+// --+ options: json=compute, stochastic +--
+
+var y x z ;
+
+varexo ex ey ez;
+
+parameters a_y_1 a_y_2 b_y_1 b_y_2 b_x_1 b_x_2 gamma; // VAR parameters
+
+parameters beta e_c_m c_z_1 c_z_2;               // PAC equation parameters
+
+a_y_1 =  .2;
+a_y_2 =  .3;
+b_y_1 =  .1;
+b_y_2 =  .4;
+b_x_1 = -.1;
+b_x_2 = -.2;
+
+beta  =  .9;
+e_c_m =  .1;
+c_z_1 =  .7;
+c_z_2 = -.3;
+
+gamma =  .7;
+
+var_model(model_name=toto, eqtags=['eq:x', 'eq:y']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = a_y_1*y(-1) + a_y_2*diff(x(-1)) + b_y_1*y(-2) + b_y_2*diff(x(-2)) + ey ;
+
+[name='eq:x']
+diff(x) = b_x_1*y(-2) + b_x_2*diff(x(-1)) + ex ;
+
+[name='eq:pac']
+diff(z) = gamma*(e_c_m*(x(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-gamma)*ez;
+
+end;
+
+shocks;
+    var ey = 1.0;
+    var ex = 1.0;
+    var ez = 1.0;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
\ No newline at end of file
diff --git a/tests/pac/var-3/clean b/tests/pac/var-3/clean
new file mode 100755
index 0000000000000000000000000000000000000000..be0d5e00cdb49fa48f99aa6470ff0578973bbce3
--- /dev/null
+++ b/tests/pac/var-3/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm -rf +example
+rm -f example*.mat
+rm -f example.log
\ No newline at end of file
diff --git a/tests/pac/var-3/example.mod b/tests/pac/var-3/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..67f8f74777f9402928b71623caa275ea99456cb9
--- /dev/null
+++ b/tests/pac/var-3/example.mod
@@ -0,0 +1,58 @@
+// --+ options: json=compute, stochastic +--
+
+var y x z;
+
+varexo ex ey ez ;
+
+parameters a_y_1 a_y_2 b_y_1 b_y_2 b_x_1 b_x_2 g; // VAR parameters
+
+parameters beta e_c_m c_z_1 c_z_2;               // PAC equation parameters
+
+a_y_1 =  .2;
+a_y_2 =  .3;
+b_y_1 =  .1;
+b_y_2 =  .4;
+b_x_1 = -.1;
+b_x_2 = -.2;
+
+beta  =  .9;
+e_c_m =  .1;
+c_z_1 =  .7;
+c_z_2 = -.3;
+
+g = .02;
+
+var_model(model_name=toto, eqtags=['eq:x', 'eq:y']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = a_y_1*y(-1) + a_y_2*diff(x(-1)) + b_y_1*y(-2) + b_y_2*diff(x(-2)) + ey ;
+
+[name='eq:x']
+diff(x) = b_x_1*y(-2) + b_x_2*diff(x(-1)) + ex ;
+
+[name='eq:pac']
+diff(z) = e_c_m*(x(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ey = 1.0;
+    var ex = 1.0;
+    var ez = 1.0;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
\ No newline at end of file
diff --git a/tests/pac/var-4/clean b/tests/pac/var-4/clean
new file mode 100755
index 0000000000000000000000000000000000000000..be0d5e00cdb49fa48f99aa6470ff0578973bbce3
--- /dev/null
+++ b/tests/pac/var-4/clean
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf example
+rm -rf +example
+rm -f example*.mat
+rm -f example.log
\ No newline at end of file
diff --git a/tests/pac/var-4/example.mod b/tests/pac/var-4/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..9716e04aee927b4a80adfc9d223c8c51394ebaaa
--- /dev/null
+++ b/tests/pac/var-4/example.mod
@@ -0,0 +1,58 @@
+// --+ options: json=compute, stochastic +--
+
+var y x z;
+
+varexo ex ey ez;
+
+parameters a_y_1 a_y_2 b_y_1 b_y_2 b_x_1 b_x_2 ; // VAR parameters
+
+parameters g beta e_c_m c_z_1 c_z_2;               // PAC equation parameters
+
+a_y_1 =  .2;
+a_y_2 =  .3;
+b_y_1 =  .1;
+b_y_2 =  .4;
+b_x_1 = -.1;
+b_x_2 = -.2;
+
+beta  =  .9;
+e_c_m =  .1;
+c_z_1 =  .7;
+c_z_2 = -.3;
+
+g = .1;
+
+var_model(model_name=toto, eqtags=['eq:x', 'eq:y']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman, growth=g);
+
+model;
+
+[name='eq:y']
+y = a_y_1*y(-1) + a_y_2*diff(x(-1)) + b_y_1*y(-2) + b_y_2*diff(x(-2)) + ey ;
+
+[name='eq:x']
+diff(x) = b_x_1*y(-2) + b_x_2*diff(x(-1)) + g*(1-b_x_2)  + ex ;
+
+[name='eq:pac']
+diff(z) = e_c_m*(x(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex = 1.0;
+    var ey = 1.0;
+    var ez = 1.0;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
\ No newline at end of file
diff --git a/tests/pac/var-5/clean b/tests/pac/var-5/clean
new file mode 100755
index 0000000000000000000000000000000000000000..20de477e3c9a5d9c2bf28cd2ebc98d5cffec4523
--- /dev/null
+++ b/tests/pac/var-5/clean
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+rm -rf example
+rm -rf +example
+rm -f example*.mat
+rm -f example.log
+rm -rf substitution
+rm -rf +substitution
+rm -f substitution*.mat
+rm -f substitution.log
diff --git a/tests/pac/var-5/example.mod b/tests/pac/var-5/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..1368f3fb2427d280e8029acc1045954fe0f72c89
--- /dev/null
+++ b/tests/pac/var-5/example.mod
@@ -0,0 +1,73 @@
+// --+ options: json=compute, stochastic +--
+
+var y x z;
+
+varexo ex ey ez;
+
+parameters a_y_1 a_y_2 b_y_1 b_y_2 b_x_1 b_x_2 ; // VAR parameters
+
+parameters g beta e_c_m c_z_1 c_z_2;               // PAC equation parameters
+
+a_y_1 =  .2;
+a_y_2 =  .3;
+b_y_1 =  .1;
+b_y_2 =  .4;
+b_x_1 = -.1;
+b_x_2 = -.2;
+
+beta  =  .9;
+e_c_m =  .1;
+c_z_1 =  .7;
+c_z_2 = -.3;
+
+g = .1;
+
+var_model(model_name=toto, eqtags=['eq:x', 'eq:y']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman, growth=g);
+
+model;
+
+[name='eq:y']
+y = a_y_1*y(-1) + a_y_2*diff(x(-1)) + b_y_1*y(-2) + b_y_2*diff(x(-2)) + ey ;
+
+[name='eq:x']
+diff(x) = b_x_1*y(-2) + b_x_2*diff(x(-1)) + g*(1-b_x_2)  + ex ;
+
+[name='eq:pac']
+diff(z) = e_c_m*(x(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex = 1.0;
+    var ey = 1.0;
+    var ez = 1.0;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 20 periods
+set_dynare_seed('default');
+TrueData = simul_backward_model(initialconditions, 20);
+
+// Print expanded PAC_EXPECTATION term.
+pac.print('pacman', 'eq:pac');
+
+verbatim;
+  set_dynare_seed('default');
+  y = zeros(M_.endo_nbr,1);
+  y(1:M_.orig_endo_nbr) = rand(M_.orig_endo_nbr, 1);
+  x = randn(M_.exo_nbr,1);
+  y = example.set_auxiliary_variables(y, x, M_.params);
+  y = [y(find(M_.lead_lag_incidence(1,:))); y];
+  [residual, g1] = example.dynamic(y, x', M_.params, oo_.steady_state, 1);
+  save('example.mat', 'residual', 'g1', 'TrueData');
+end;
diff --git a/tests/pac/var-5/substitution.mod b/tests/pac/var-5/substitution.mod
new file mode 100644
index 0000000000000000000000000000000000000000..41ae58da39a7597ed2548729ae5e77bc019db643
--- /dev/null
+++ b/tests/pac/var-5/substitution.mod
@@ -0,0 +1,79 @@
+// --+ options: transform_unary_ops, json=compute, stochastic +--
+
+var y x z;
+
+varexo ex ey ez;
+
+parameters a_y_1 a_y_2 b_y_1 b_y_2 b_x_1 b_x_2 g; // VAR parameters
+
+parameters e_c_m c_z_1 c_z_2;               // PAC equation parameters
+
+a_y_1 =  .2;
+a_y_2 =  .3;
+b_y_1 =  .1;
+b_y_2 =  .4;
+b_x_1 = -.1;
+b_x_2 = -.2;
+
+g = .1;
+
+e_c_m =  .1;
+c_z_1 =  .7;
+c_z_2 = -.3;
+
+@#include "example/model/pac-expectations/eq0-pacman-parameters.inc"
+
+model;
+
+[name='eq:y']
+y = a_y_1*y(-1) + a_y_2*diff(x(-1)) + b_y_1*y(-2) + b_y_2*diff(x(-2)) + ey ;
+
+[name='eq:x']
+diff(x) = b_x_1*y(-2) + b_x_2*diff(x(-1)) + g*(1-b_x_2)  + ex ;
+
+[name='eq:pac']
+diff(z) = e_c_m*(x(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) +
+@#include "example/model/pac-expectations/eq0-pacman-growth-neutrality-correction.inc"
++
+@#include "example/model/pac-expectations/eq0-pacman-expression.inc"
++ ez;
+
+end;
+
+shocks;
+    var ex = 1.0;
+    var ey = 1.0;
+    var ez = 1.0;
+end;
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 20 periods
+set_dynare_seed('default');
+TrueData = simul_backward_model(initialconditions, 20);
+
+verbatim;
+  set_dynare_seed('default');
+  y = zeros(M_.endo_nbr,1);
+  y(1:M_.orig_endo_nbr) = rand(M_.orig_endo_nbr, 1);
+  x = randn(M_.exo_nbr,1);
+  y = substitution.set_auxiliary_variables(y, x, M_.params);
+  y = [y(find(M_.lead_lag_incidence(1,:))); y];
+  example = load('example.mat');
+  [residual, g1] = substitution.dynamic(y, x', M_.params, oo_.steady_state, 1);
+end;
+
+if max(abs(example.TrueData.data(:)-TrueData.data(:)))>1e-9
+   error('Simulations do not match.')
+end
+
+if ~isequal(length(residual), length(example.residual)) || max(abs(example.residual-residual))>1e-8
+  warning('Residuals do not match!')
+end
+
+if ~isequal(length(g1(:)), length(example.g1(:))) || max(abs(example.g1(:)-g1(:)))>1e-8
+  warning('Jacobian matrices do not match!')
+end
+
+delete('example.mat');
\ No newline at end of file
diff --git a/tests/pac/var-6/clean b/tests/pac/var-6/clean
new file mode 100755
index 0000000000000000000000000000000000000000..20de477e3c9a5d9c2bf28cd2ebc98d5cffec4523
--- /dev/null
+++ b/tests/pac/var-6/clean
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+rm -rf example
+rm -rf +example
+rm -f example*.mat
+rm -f example.log
+rm -rf substitution
+rm -rf +substitution
+rm -f substitution*.mat
+rm -f substitution.log
diff --git a/tests/pac/var-6/example.mod b/tests/pac/var-6/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..f2e94f5175261d5db4c137da910c08c3a26494bf
--- /dev/null
+++ b/tests/pac/var-6/example.mod
@@ -0,0 +1,77 @@
+// --+ options: json=compute, stochastic +--
+
+var y x z u;
+
+varexo ex ey ez eu;
+
+parameters a_y_1 a_y_2 b_y_1 b_y_2 b_x_1 b_x_2 ; // VAR parameters
+
+parameters g beta e_c_m c_z_1 c_z_2;               // PAC equation parameters
+
+a_y_1 =  .2;
+a_y_2 =  .3;
+b_y_1 =  .1;
+b_y_2 =  .4;
+b_x_1 = -.1;
+b_x_2 = -.2;
+
+beta  =  .9;
+e_c_m =  .1;
+c_z_1 =  .7;
+c_z_2 = -.3;
+
+g = .1;
+
+var_model(model_name=toto, eqtags=['eq:x', 'eq:y']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman, growth=diff(u(-1)));
+
+model;
+
+[name='eq:u']
+diff(u) = g + eu;
+
+[name='eq:y']
+y = a_y_1*y(-1) + a_y_2*diff(x(-1)) + b_y_1*y(-2) + b_y_2*diff(x(-2)) + ey ;
+
+[name='eq:x']
+diff(x) = b_x_1*y(-2) + b_x_2*diff(x(-1)) + g*(1-b_x_2)  + ex ;
+
+[name='eq:pac']
+diff(z) = e_c_m*(x(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex = 1.0;
+    var ey = 1.0;
+    var ez = 1.0;
+    var eu = 0.1;
+end;
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 20 periods
+set_dynare_seed('default');
+TrueData = simul_backward_model(initialconditions, 20);
+
+// Print expanded PAC_EXPECTATION term.
+pac.print('pacman', 'eq:pac');
+
+verbatim;
+  set_dynare_seed('default');
+  y = zeros(M_.endo_nbr,1);
+  y(1:M_.orig_endo_nbr) = rand(M_.orig_endo_nbr, 1);
+  x = randn(M_.exo_nbr,1);
+  y = example.set_auxiliary_variables(y, x, M_.params);
+  y = [y(find(M_.lead_lag_incidence(1,:))); y];
+  [residual, g1] = example.dynamic(y, x', M_.params, oo_.steady_state, 1);
+  save('example.mat', 'residual', 'g1', 'TrueData');
+end;
diff --git a/tests/pac/var-6/substitution.mod b/tests/pac/var-6/substitution.mod
new file mode 100644
index 0000000000000000000000000000000000000000..f412bf6556709587ad549f7c74b84df453a7b084
--- /dev/null
+++ b/tests/pac/var-6/substitution.mod
@@ -0,0 +1,85 @@
+// --+ options: transform_unary_ops, json=compute, stochastic +--
+
+var y x z u;
+
+varexo ex ey ez eu;
+
+parameters a_y_1 a_y_2 b_y_1 b_y_2 b_x_1 b_x_2 g; // VAR parameters
+
+parameters e_c_m c_z_1 c_z_2;               // PAC equation parameters
+
+a_y_1 =  .2;
+a_y_2 =  .3;
+b_y_1 =  .1;
+b_y_2 =  .4;
+b_x_1 = -.1;
+b_x_2 = -.2;
+
+g = .1;
+
+e_c_m =  .1;
+c_z_1 =  .7;
+c_z_2 = -.3;
+
+@#include "example/model/pac-expectations/eq0-pacman-parameters.inc"
+
+model;
+
+  [name='eq:u']
+  diff(u) = g + eu;
+
+  [name='eq:y']
+  y = a_y_1*y(-1) + a_y_2*diff(x(-1)) + b_y_1*y(-2) + b_y_2*diff(x(-2)) + ey ;
+
+  [name='eq:x']
+  diff(x) = b_x_1*y(-2) + b_x_2*diff(x(-1)) + g*(1-b_x_2)  + ex ;
+
+  [name='eq:pac']
+  diff(z) = e_c_m*(x(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) +
+  @#include "example/model/pac-expectations/eq0-pacman-growth-neutrality-correction.inc"
+  +
+  @#include "example/model/pac-expectations/eq0-pacman-expression.inc"
+  + ez;
+
+end;
+
+shocks;
+  var ex = 1.0;
+  var ey = 1.0;
+  var ez = 1.0;
+  var eu = 0.1;
+end;
+
+// Set initial conditions to zero. Please use more sensible values if any...
+initialconditions = dseries(zeros(10, M_.endo_nbr+M_.exo_nbr), 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 20 periods
+set_dynare_seed('default');
+TrueData = simul_backward_model(initialconditions, 20);
+
+verbatim;
+
+  set_dynare_seed('default');
+  y = zeros(M_.endo_nbr,1);
+  y(1:M_.orig_endo_nbr) = rand(M_.orig_endo_nbr, 1);
+  x = randn(M_.exo_nbr,1);
+  y = substitution.set_auxiliary_variables(y, x, M_.params);
+  y = [y(find(M_.lead_lag_incidence(1,:))); y];
+  example = load('example.mat');
+  [residual, g1] = substitution.dynamic(y, x', M_.params, oo_.steady_state, 1);
+
+  if max(abs(example.TrueData.data(:)-TrueData.data(:)))>1e-9
+    error('Simulations do not match.')
+  end
+
+  if ~isequal(length(residual), length(example.residual)) || max(abs(example.residual-residual))>1e-8
+    warning('Residuals do not match!')
+  end
+
+  if ~isequal(length(g1(:)), length(example.g1(:))) || max(abs(example.g1(:)-g1(:)))>1e-8
+    warning('Jacobian matrices do not match!')
+  end
+
+  delete('example.mat');
+
+end;
diff --git a/tests/ramst_mshocks_vec.mod b/tests/ramst_mshocks_vec.mod
new file mode 100644
index 0000000000000000000000000000000000000000..89c0ad2daca3a17600fc69e6be96874278e546c8
--- /dev/null
+++ b/tests/ramst_mshocks_vec.mod
@@ -0,0 +1,46 @@
+// Test mshocks block
+
+var c k;
+varexo x;
+
+parameters alph gam delt bet aa;
+alph=0.5;
+gam=0.5;
+delt=0.02;
+bet=0.05;
+aa=0.5;
+
+
+model;
+c + k - aa*x*k(-1)^alph - (1-delt)*k(-1);
+c^(-gam) - (1+bet)^(-1)*(aa*alph*x(+1)*k^(alph-1) + 1 - delt)*c(+1)^(-gam);
+end;
+
+initval;
+x = 2;
+k = ((delt+bet)/(1.0*aa*x*alph))^(1/(alph-1));
+c = aa*x*k^alph-delt*k;
+end;
+
+steady;
+
+check;
+
+xvalues = [1.2; 0.8; 0.8];
+
+mshocks;
+var x;
+periods 1:3;
+values (xvalues);
+end;
+
+perfect_foresight_setup(periods=200);
+perfect_foresight_solver;
+
+rplot c;
+rplot k;
+
+if ~all(oo_.exo_simul(M_.maximum_lag+(1:3)) == [ 2.4; 1.6; 1.6]) ...
+    || ~all(oo_.exo_simul(M_.maximum_lag+(4:200)) == 2)
+  error("mshocks not correctly applied")
+end
diff --git a/tests/shock_decomposition/shock_decomposition_backward.mod b/tests/shock_decomposition/shock_decomposition_backward.mod
new file mode 100644
index 0000000000000000000000000000000000000000..930fb03c3e066a0dc1b52429fac21677187cf442
--- /dev/null
+++ b/tests/shock_decomposition/shock_decomposition_backward.mod
@@ -0,0 +1,146 @@
+// --+ options: json=compute, stochastic +--
+
+/* This file tests the matlab/backward/shock_decomposition_backward.m routine,
+   used for shock decomposition of nonlinear backward models */
+
+var x1 x2 x3 x1bar x2bar z y x u v s;
+
+varexo ex1
+       ex2
+       ex1bar (used='estimationonly')
+       ex2bar (used='estimationonly')
+       ez
+       ey
+       ex
+       eu
+       ev
+       es;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 c_z_dx2 c_z_u c_z_dv c_z_s cx cy beta
+       lambda
+       px3;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+c_z_dx2 = .3;
+c_z_u = .3;
+c_z_dv = .4;
+c_z_s  = -.2; 
+cx = 1.0;
+cy = 1.0;
+
+
+lambda = 0.5; // Share of optimizing agents.
+
+px3 = -.1;
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:s']
+s = .3*s(-1) - .1*s(-2) + es;
+
+[name='eq:diff(v)']
+diff(v) = .5*diff(v(-1)) + ev;
+
+[name='eq:u']
+u = .5*u(-1) - .2*u(-2) + eu;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x3']
+x3 = px3*x + y ;
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + c_z_s*s + c_z_dv*diff(v) ) + (1-lambda)*( cy*y + cx*x) + c_z_u*u + c_z_dx2*diff(x2) + ez;
+
+end;
+
+shocks;
+  var ex1 = 1.0;
+  var ex2 = 1.0;
+  var ex1bar = 1.0;
+  var ex2bar = 1.0;
+  var ez = 1.0;
+  var ey = 0.1;
+  var ex = 0.1;
+  var eu = 0.05;
+  var ev = 0.05;
+  var es = 0.07;
+end;
+
+shock_groups;
+  g1 = ex, ey, ez;
+  g2 = eu, ev;
+end;
+
+
+// Initialize the PAC model (build the Companion VAR representation for the auxiliary model).
+pac.initialize('pacman');
+
+// Update the parameters of the PAC expectation model (h0 and h1 vectors).
+pac.update.expectation('pacman');
+
+// Set initial conditions to zero for non logged variables, and one for logged variables
+init = zeros(10, M_.endo_nbr+M_.exo_nbr);
+initialconditions = dseries(init, 2000Q1, vertcat(M_.endo_names,M_.exo_names));
+
+// Simulate the model for 500 periods
+TrueData = simul_backward_model(initialconditions, 500);
+
+decomposition = shock_decomposition_backward(TrueData, initialconditions, { 'g1', 'g2', 'es' }, { 'z', 'y', 'u'});
+
+% Verify that y is only influenced by g1 (which contains ey)
+y_idx = find(strcmp(M_.endo_names, 'y'));
+if ~(all(all(decomposition(y_idx, 2:3, :) == 0)) && all(all(decomposition(y_idx, 1, :) ~= 0)))
+  error('Wrong decomposition for y')
+end
+
+% Verify that u is only influenced by g2 (which contains eu)
+u_idx = find(strcmp(M_.endo_names, 'u'));
+if ~(all(all(decomposition(u_idx, [1 3], :) == 0)) && all(all(decomposition(u_idx, 2, :) ~= 0)))
+  error('Wrong decomposition for u')
+end
diff --git a/tests/steady_state/example1_block_trust_region.mod b/tests/steady_state/example1_block_trust_region.mod
new file mode 100644
index 0000000000000000000000000000000000000000..54643e08375d21832cdc604d81272300d0df88ff
--- /dev/null
+++ b/tests/steady_state/example1_block_trust_region.mod
@@ -0,0 +1,47 @@
+// Test block trust region nonlinear solver (solve_algo=13)
+var y, c, k, a, h, b;
+varexo e, u;
+
+parameters beta, rho, alpha, delta, theta, psi, tau;
+
+alpha = 0.36;
+rho   = 0.95;
+tau   = 0.025;
+beta  = 0.99;
+delta = 0.025;
+psi   = 0;
+theta = 2.95;
+
+phi   = 0.1;
+
+model;
+c*theta*h^(1+psi)=(1-alpha)*y;
+k = beta*(((exp(b)*c)/(exp(b(+1))*c(+1)))
+    *(exp(b(+1))*alpha*y(+1)+(1-delta)*k));
+y = exp(a)*(k(-1)^alpha)*(h^(1-alpha));
+k = exp(b)*(y-c)+(1-delta)*k(-1);
+a = rho*a(-1)+tau*b(-1) + e;
+b = tau*a(-1)+rho*b(-1) + u;
+end;
+
+initval;
+y = 1;
+c = 0.8;
+h = 0.3;
+k = 10;
+a = 0;
+b = 0;
+e = 0;
+u = 0;
+end;
+
+options_.debug = true;
+steady(solve_algo=13);
+
+shocks;
+var e; stderr 0.009;
+var u; stderr 0.009;
+var e, u = phi*0.009*0.009;
+end;
+
+stoch_simul(order=1,nomoments,irf=0);
diff --git a/tests/test_aggregate_routine_1_2.m b/tests/test_aggregate_routine_1_2.m
new file mode 100644
index 0000000000000000000000000000000000000000..795d7d4d028c0dfe440c87bb5ce3bce9d01f2275
--- /dev/null
+++ b/tests/test_aggregate_routine_1_2.m
@@ -0,0 +1,36 @@
+top_test_dir = getenv('TOP_TEST_DIR');
+addpath([top_test_dir filesep() '..' filesep() 'matlab']);
+
+% Test Dynare Version
+if ~strcmp(dynare_version(), getenv('DYNARE_VERSION'))
+  error('Incorrect version of Dynare is being tested')
+end
+
+% To add default directories, empty dseries objects
+dynare_config();
+
+disp('');
+disp(['***  TESTING: test_aggregate_routine_1_2.m.trs ***']);
+try
+    aggregate('toto2.mod', {}, 'ecb/aggregate/1', 'ecb/aggregate/2');
+    testFailed = false;
+catch
+    testFailed = true;
+end
+
+cd(getenv('TOP_TEST_DIR'));
+fid = fopen('test_aggregate_routine_1_2.m.trs', 'w+');
+if testFailed
+  fprintf(fid,':test-result: FAIL\n');
+  fprintf(fid,':number-tests: 1\n');
+  fprintf(fid,':number-failed-tests: 1\n');
+  fprintf(fid,':list-of-failed-tests: test_aggregate_routine_1_2.m\n');
+else
+  fprintf(fid,':test-result: PASS\n');
+  fprintf(fid,':number-tests: 1\n');
+  fprintf(fid,':number-failed-tests: 0\n');
+  fprintf(fid,':list-of-passed-tests: test_aggregate_routine_1_2.m\n');
+end
+fprintf(fid,':elapsed-time: %f\n',0.0);
+fclose(fid);
+exit;
\ No newline at end of file
diff --git a/tests/test_aggregate_routine_1_2_3.m b/tests/test_aggregate_routine_1_2_3.m
new file mode 100644
index 0000000000000000000000000000000000000000..91b44134f42bfcbdcdff8aa9b805cf5aaf0c8bcf
--- /dev/null
+++ b/tests/test_aggregate_routine_1_2_3.m
@@ -0,0 +1,36 @@
+top_test_dir = getenv('TOP_TEST_DIR');
+addpath([top_test_dir filesep() '..' filesep() 'matlab']);
+
+% Test Dynare Version
+if ~strcmp(dynare_version(), getenv('DYNARE_VERSION'))
+  error('Incorrect version of Dynare is being tested')
+end
+
+% To add default directories, empty dseries objects
+dynare_config();
+
+disp('');
+disp(['***  TESTING: test_aggregate_routine_1_2_3.m.trs ***']);
+try
+    aggregate('toto3.mod', {}, 'ecb/aggregate/1', 'ecb/aggregate/2', 'ecb/aggregate/3');
+    testFailed = false;
+catch
+    testFailed = true;
+end
+
+cd(getenv('TOP_TEST_DIR'));
+fid = fopen('test_aggregate_routine_1_2_3.m.trs', 'w+');
+if testFailed
+  fprintf(fid,':test-result: FAIL\n');
+  fprintf(fid,':number-tests: 1\n');
+  fprintf(fid,':number-failed-tests: 1\n');
+  fprintf(fid,':list-of-failed-tests: test_aggregate_routine_1_2_3.m\n');
+else
+  fprintf(fid,':test-result: PASS\n');
+  fprintf(fid,':number-tests: 1\n');
+  fprintf(fid,':number-failed-tests: 0\n');
+  fprintf(fid,':list-of-passed-tests: test_aggregate_routine_1_2_3.m\n');
+end
+fprintf(fid,':elapsed-time: %f\n',0.0);
+fclose(fid);
+exit;
\ No newline at end of file
diff --git a/tests/trend-component-and-var-models/legacy/tcm1.mod b/tests/trend-component-and-var-models/legacy/tcm1.mod
new file mode 100644
index 0000000000000000000000000000000000000000..3bf355129382d318dc97d1ada3792015c5ccff30
--- /dev/null
+++ b/tests/trend-component-and-var-models/legacy/tcm1.mod
@@ -0,0 +1,138 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112 A113 A114
+           A121 A122 A123 A124
+           A131 A132 A133 A134
+           A141 A142 A143 A144
+           A211 A212 A213 A214
+           A221 A222 A223 A224
+           A231 A232 A233 A234
+           A241 A242 A243 A244
+           A311 A312 A313 A314
+           A321 A322 A323 A324
+           A331 A332 A333 A334
+           A341 A342 A343 A344
+           B11 B12 B21 B22;
+
+A1 = randn(4);
+A2 = randn(4);
+A3 = randn(4);
+
+A1(3:4,:) = 0;
+A2(3:4,:) = 0;
+A3(3:4,:) = 0;
+
+A1(1:2,3:4) = 0;
+A2(1:2,3:4) = 0;
+A3(1:2,3:4) = 0;
+
+A1(3:4,3:4) = eye(2); // y3 and y4 are pure random walks.
+
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A113 = A1(1,3);
+A114 = A1(1,4);
+A121 = A1(2,1);
+A122 = A1(2,2);
+A123 = A1(2,3);
+A124 = A1(2,4);
+A131 = A1(3,1);
+A132 = A1(3,2);
+A133 = A1(3,3);
+A134 = A1(3,4);
+A141 = A1(4,1);
+A142 = A1(4,2);
+A143 = A1(4,3);
+A144 = A1(4,4);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A213 = A2(1,3);
+A214 = A2(1,4);
+A221 = A2(2,1);
+A222 = A2(2,2);
+A223 = A2(2,3);
+A224 = A2(2,4);
+A231 = A2(3,1);
+A232 = A2(3,2);
+A233 = A2(3,3);
+A234 = A2(3,4);
+A241 = A2(4,1);
+A242 = A2(4,2);
+A243 = A2(4,3);
+A244 = A2(4,4);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A313 = A3(1,3);
+A314 = A3(1,4);
+A321 = A3(2,1);
+A322 = A3(2,2);
+A323 = A3(2,3);
+A324 = A3(2,4);
+A331 = A3(3,1);
+A332 = A3(3,2);
+A333 = A3(3,3);
+A334 = A3(3,4);
+A341 = A3(4,1);
+A342 = A3(4,2);
+A343 = A3(4,3);
+A344 = A3(4,4);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+trend_component_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4'], targets=['eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+end;
+
+[EC, AR, T] = get_companion_matrix_legacy('toto');
+
+if max(max(abs(EC-B)))>1e-12
+   error('Error component matrix is wrong.')
+end
+
+A1fake = oo_.trend_component.toto.ar(:,:,1);
+A1fake(1:2,3:4) = .0;
+
+if max(max(abs(A1fake-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(oo_.trend_component.toto.ar(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(oo_.trend_component.toto.ar(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
\ No newline at end of file
diff --git a/tests/trend-component-and-var-models/legacy/tcm2.mod b/tests/trend-component-and-var-models/legacy/tcm2.mod
new file mode 100644
index 0000000000000000000000000000000000000000..f5d0bc306974accf08ad0bb7d9f5cc5748852f50
--- /dev/null
+++ b/tests/trend-component-and-var-models/legacy/tcm2.mod
@@ -0,0 +1,135 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112 A113 A114
+           A121 A122 A123 A124
+           A131 A132 A133 A134
+           A141 A142 A143 A144
+           A211 A212 A213 A214
+           A221 A222 A223 A224
+           A231 A232 A233 A234
+           A241 A242 A243 A244
+           A311 A312 A313 A314
+           A321 A322 A323 A324
+           A331 A332 A333 A334
+           A341 A342 A343 A344
+           B11 B12 B21 B22;
+
+A1 = randn(4);
+A2 = randn(4);
+A3 = randn(4);
+
+A1(3:4,:) = 0;
+A2(3:4,:) = 0;
+A3(3:4,:) = 0;
+
+A1(1:2,3:4) = 0;
+A2(1:2,3:4) = 0;
+A3(1:2,3:4) = 0;
+
+A1(3:4,3:4) = eye(2); // y3 and y4 are pure random walks.
+
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A113 = A1(1,3);
+A114 = A1(1,4);
+A121 = A1(2,1);
+A122 = A1(2,2);
+A123 = A1(2,3);
+A124 = A1(2,4);
+A131 = A1(3,1);
+A132 = A1(3,2);
+A133 = A1(3,3);
+A134 = A1(3,4);
+A141 = A1(4,1);
+A142 = A1(4,2);
+A143 = A1(4,3);
+A144 = A1(4,4);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A213 = A2(1,3);
+A214 = A2(1,4);
+A221 = A2(2,1);
+A222 = A2(2,2);
+A223 = A2(2,3);
+A224 = A2(2,4);
+A231 = A2(3,1);
+A232 = A2(3,2);
+A233 = A2(3,3);
+A234 = A2(3,4);
+A241 = A2(4,1);
+A242 = A2(4,2);
+A243 = A2(4,3);
+A244 = A2(4,4);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A313 = A3(1,3);
+A314 = A3(1,4);
+A321 = A3(2,1);
+A322 = A3(2,2);
+A323 = A3(2,3);
+A324 = A3(2,4);
+A331 = A3(3,1);
+A332 = A3(3,2);
+A333 = A3(3,3);
+A334 = A3(3,4);
+A341 = A3(4,1);
+A342 = A3(4,2);
+A343 = A3(4,3);
+A344 = A3(4,4);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+trend_component_model(model_name=toto, eqtags=['eq:y1', 'eq:y4', 'eq:y2', 'eq:y3'], targets=['eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+end;
+
+[EC, AR, T] = get_companion_matrix_legacy('toto');
+
+if max(max(abs(EC-B)))>1e-12
+   error('Error component matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,1)-A1(1:2,1:2))))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2(1:2,1:2))))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3(1:2,1:2))))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
\ No newline at end of file
diff --git a/tests/trend-component-and-var-models/legacy/tcm3.mod b/tests/trend-component-and-var-models/legacy/tcm3.mod
new file mode 100644
index 0000000000000000000000000000000000000000..80ae806f4f04f0d7ded1ef652f6593600b233ec5
--- /dev/null
+++ b/tests/trend-component-and-var-models/legacy/tcm3.mod
@@ -0,0 +1,135 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112 A113 A114
+           A121 A122 A123 A124
+           A131 A132 A133 A134
+           A141 A142 A143 A144
+           A211 A212 A213 A214
+           A221 A222 A223 A224
+           A231 A232 A233 A234
+           A241 A242 A243 A244
+           A311 A312 A313 A314
+           A321 A322 A323 A324
+           A331 A332 A333 A334
+           A341 A342 A343 A344
+           B11 B12 B21 B22;
+
+A1 = randn(4);
+A2 = randn(4);
+A3 = randn(4);
+
+A1(3:4,:) = 0;
+A2(3:4,:) = 0;
+A3(3:4,:) = 0;
+
+A1(1:2,3:4) = 0;
+A2(1:2,3:4) = 0;
+A3(1:2,3:4) = 0;
+
+A1(3:4,3:4) = eye(2); // y3 and y4 are pure random walks.
+
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A113 = A1(1,3);
+A114 = A1(1,4);
+A121 = A1(2,1);
+A122 = A1(2,2);
+A123 = A1(2,3);
+A124 = A1(2,4);
+A131 = A1(3,1);
+A132 = A1(3,2);
+A133 = A1(3,3);
+A134 = A1(3,4);
+A141 = A1(4,1);
+A142 = A1(4,2);
+A143 = A1(4,3);
+A144 = A1(4,4);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A213 = A2(1,3);
+A214 = A2(1,4);
+A221 = A2(2,1);
+A222 = A2(2,2);
+A223 = A2(2,3);
+A224 = A2(2,4);
+A231 = A2(3,1);
+A232 = A2(3,2);
+A233 = A2(3,3);
+A234 = A2(3,4);
+A241 = A2(4,1);
+A242 = A2(4,2);
+A243 = A2(4,3);
+A244 = A2(4,4);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A313 = A3(1,3);
+A314 = A3(1,4);
+A321 = A3(2,1);
+A322 = A3(2,2);
+A323 = A3(2,3);
+A324 = A3(2,4);
+A331 = A3(3,1);
+A332 = A3(3,2);
+A333 = A3(3,3);
+A334 = A3(3,4);
+A341 = A3(4,1);
+A342 = A3(4,2);
+A343 = A3(4,3);
+A344 = A3(4,4);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+trend_component_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4'], targets=['eq:y4', 'eq:y3']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+end;
+
+[EC, AR, T] = get_companion_matrix_legacy('toto');
+
+if max(max(abs(EC-B)))>1e-12
+   error('Error component matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,1)-A1(1:2,1:2))))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2(1:2,1:2))))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3(1:2,1:2))))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
\ No newline at end of file
diff --git a/tests/trend-component-and-var-models/legacy/tcm4.mod b/tests/trend-component-and-var-models/legacy/tcm4.mod
new file mode 100644
index 0000000000000000000000000000000000000000..0b48ce1abe409cd508b85ef53cc249ff2a070dde
--- /dev/null
+++ b/tests/trend-component-and-var-models/legacy/tcm4.mod
@@ -0,0 +1,136 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112 A113 A114
+           A121 A122 A123 A124
+           A131 A132 A133 A134
+           A141 A142 A143 A144
+           A211 A212 A213 A214
+           A221 A222 A223 A224
+           A231 A232 A233 A234
+           A241 A242 A243 A244
+           A311 A312 A313 A314
+           A321 A322 A323 A324
+           A331 A332 A333 A334
+           A341 A342 A343 A344
+           B11 B12 B21 B22;
+
+A1 = randn(4);
+A2 = randn(4);
+A3 = randn(4);
+
+A1(3:4,:) = 0;
+A2(3:4,:) = 0;
+A3(3:4,:) = 0;
+
+A1(1:2,3:4) = 0;
+A2(1:2,3:4) = 0;
+A3(1:2,3:4) = 0;
+
+A1(3:4,3:4) = eye(2); // y3 and y4 are pure random walks.
+
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A113 = A1(1,3);
+A114 = A1(1,4);
+A121 = A1(2,1);
+A122 = A1(2,2);
+A123 = A1(2,3);
+A124 = A1(2,4);
+A131 = A1(3,1);
+A132 = A1(3,2);
+A133 = A1(3,3);
+A134 = A1(3,4);
+A141 = A1(4,1);
+A142 = A1(4,2);
+A143 = A1(4,3);
+A144 = A1(4,4);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A213 = A2(1,3);
+A214 = A2(1,4);
+A221 = A2(2,1);
+A222 = A2(2,2);
+A223 = A2(2,3);
+A224 = A2(2,4);
+A231 = A2(3,1);
+A232 = A2(3,2);
+A233 = A2(3,3);
+A234 = A2(3,4);
+A241 = A2(4,1);
+A242 = A2(4,2);
+A243 = A2(4,3);
+A244 = A2(4,4);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A313 = A3(1,3);
+A314 = A3(1,4);
+A321 = A3(2,1);
+A322 = A3(2,2);
+A323 = A3(2,3);
+A324 = A3(2,4);
+A331 = A3(3,1);
+A332 = A3(3,2);
+A333 = A3(3,3);
+A334 = A3(3,4);
+A341 = A3(4,1);
+A342 = A3(4,2);
+A343 = A3(4,3);
+A344 = A3(4,4);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+trend_component_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4'], targets=['eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+end;
+
+[EC, AR, T] = get_companion_matrix_legacy('toto');
+
+if max(max(abs(EC-B)))>1e-12
+   error('Error component matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,1)-A1(1:2,1:2))))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2(1:2,1:2))))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3(1:2,1:2))))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
\ No newline at end of file
diff --git a/tests/trend-component-and-var-models/legacy/tcm5.mod b/tests/trend-component-and-var-models/legacy/tcm5.mod
new file mode 100644
index 0000000000000000000000000000000000000000..0ae4b72c907f9e600d318a7c99a40a212e9930ea
--- /dev/null
+++ b/tests/trend-component-and-var-models/legacy/tcm5.mod
@@ -0,0 +1,136 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112 A113 A114
+           A121 A122 A123 A124
+           A131 A132 A133 A134
+           A141 A142 A143 A144
+           A211 A212 A213 A214
+           A221 A222 A223 A224
+           A231 A232 A233 A234
+           A241 A242 A243 A244
+           A311 A312 A313 A314
+           A321 A322 A323 A324
+           A331 A332 A333 A334
+           A341 A342 A343 A344
+           B11 B12 B21 B22;
+
+A1 = randn(4);
+A2 = randn(4);
+A3 = randn(4);
+
+A1(3:4,:) = 0;
+A2(3:4,:) = 0;
+A3(3:4,:) = 0;
+
+A1(1:2,3:4) = 0;
+A2(1:2,3:4) = 0;
+A3(1:2,3:4) = 0;
+
+A1(3:4,3:4) = eye(2); // y3 and y4 are pure random walks.
+
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A113 = A1(1,3);
+A114 = A1(1,4);
+A121 = A1(2,1);
+A122 = A1(2,2);
+A123 = A1(2,3);
+A124 = A1(2,4);
+A131 = A1(3,1);
+A132 = A1(3,2);
+A133 = A1(3,3);
+A134 = A1(3,4);
+A141 = A1(4,1);
+A142 = A1(4,2);
+A143 = A1(4,3);
+A144 = A1(4,4);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A213 = A2(1,3);
+A214 = A2(1,4);
+A221 = A2(2,1);
+A222 = A2(2,2);
+A223 = A2(2,3);
+A224 = A2(2,4);
+A231 = A2(3,1);
+A232 = A2(3,2);
+A233 = A2(3,3);
+A234 = A2(3,4);
+A241 = A2(4,1);
+A242 = A2(4,2);
+A243 = A2(4,3);
+A244 = A2(4,4);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A313 = A3(1,3);
+A314 = A3(1,4);
+A321 = A3(2,1);
+A322 = A3(2,2);
+A323 = A3(2,3);
+A324 = A3(2,4);
+A331 = A3(3,1);
+A332 = A3(3,2);
+A333 = A3(3,3);
+A334 = A3(3,4);
+A341 = A3(4,1);
+A342 = A3(4,2);
+A343 = A3(4,3);
+A344 = A3(4,4);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+trend_component_model(model_name=toto, eqtags=['eq:y4', 'eq:y1', 'eq:y2', 'eq:y3'], targets=['eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+end;
+
+[EC, AR, T] = get_companion_matrix_legacy('toto');
+
+if max(max(abs(EC-B)))>1e-12
+   error('Error component matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,1)-A1(1:2,1:2))))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2(1:2,1:2))))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3(1:2,1:2))))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
\ No newline at end of file
diff --git a/tests/trend-component-and-var-models/legacy/vm1.mod b/tests/trend-component-and-var-models/legacy/vm1.mod
new file mode 100644
index 0000000000000000000000000000000000000000..1869e3a05289ebe5e219a4885555d28f68b9ed05
--- /dev/null
+++ b/tests/trend-component-and-var-models/legacy/vm1.mod
@@ -0,0 +1,119 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112 A113 A114
+           A121 A122 A123 A124
+           A131 A132 A133 A134
+           A141 A142 A143 A144
+           A211 A212 A213 A214
+           A221 A222 A223 A224
+           A231 A232 A233 A234
+           A241 A242 A243 A244
+           A311 A312 A313 A314
+           A321 A322 A323 A324
+           A331 A332 A333 A334
+           A341 A342 A343 A344 ;
+
+A1 = randn(4);
+A2 = randn(4);
+A3 = randn(4);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A113 = A1(1,3);
+A114 = A1(1,4);
+A121 = A1(2,1);
+A122 = A1(2,2);
+A123 = A1(2,3);
+A124 = A1(2,4);
+A131 = A1(3,1);
+A132 = A1(3,2);
+A133 = A1(3,3);
+A134 = A1(3,4);
+A141 = A1(4,1);
+A142 = A1(4,2);
+A143 = A1(4,3);
+A144 = A1(4,4);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A213 = A2(1,3);
+A214 = A2(1,4);
+A221 = A2(2,1);
+A222 = A2(2,2);
+A223 = A2(2,3);
+A224 = A2(2,4);
+A231 = A2(3,1);
+A232 = A2(3,2);
+A233 = A2(3,3);
+A234 = A2(3,4);
+A241 = A2(4,1);
+A242 = A2(4,2);
+A243 = A2(4,3);
+A244 = A2(4,4);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A313 = A3(1,3);
+A314 = A3(1,4);
+A321 = A3(2,1);
+A322 = A3(2,2);
+A323 = A3(2,3);
+A324 = A3(2,4);
+A331 = A3(3,1);
+A332 = A3(3,2);
+A333 = A3(3,3);
+A334 = A3(3,4);
+A341 = A3(4,1);
+A342 = A3(4,2);
+A343 = A3(4,3);
+A344 = A3(4,4);
+
+var_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+y1 = A111*y1(-1) + A112*y2(-1) + A113*y3(-1) + A114*y4(-1) +
+     A211*y1(-2) + A212*y2(-2) + A213*y3(-2) + A214*y4(-2) +
+     A311*y1(-3) + A312*y2(-3) + A313*y3(-3) + A314*y4(-3) + e1; 
+
+[name='eq:y2']
+y2 = A121*y1(-1) + A122*y2(-1) + A123*y3(-1) + A124*y4(-1) +
+     A221*y1(-2) + A222*y2(-2) + A223*y3(-2) + A224*y4(-2) +
+     A321*y1(-3) + A322*y2(-3) + A323*y3(-3) + A324*y4(-3) + e2; 
+
+[name='eq:y3']
+y3 = A131*y1(-1) + A132*y2(-1) + A133*y3(-1) + A134*y4(-1) +
+     A231*y1(-2) + A232*y2(-2) + A233*y3(-2) + A234*y4(-2) +
+     A331*y1(-3) + A332*y2(-3) + A333*y3(-3) + A334*y4(-3) + e3; 
+
+[name='eq:y4']
+y4 = A141*y1(-1) + A142*y2(-1) + A143*y3(-1) + A144*y4(-1) +
+     A241*y1(-2) + A242*y2(-2) + A243*y3(-2) + A244*y4(-2) +
+     A341*y1(-3) + A342*y2(-3) + A343*y3(-3) + A344*y4(-3) + e4;
+
+end;
+
+get_companion_matrix_legacy('toto');
+
+if max(max(abs(oo_.var.toto.ar(:,:,1)-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(oo_.var.toto.ar(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(oo_.var.toto.ar(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
+
+CompanionMatrix = [A1, A2, A3;
+                   eye(4), zeros(4, 8);
+                   zeros(4), eye(4), zeros(4)];
+
+if max(max(abs(CompanionMatrix-oo_.var.toto.CompanionMatrix)))>1e-12
+   error('Companion matrix is wrong.')
+end
\ No newline at end of file
diff --git a/tests/trend-component-and-var-models/legacy/vm2.mod b/tests/trend-component-and-var-models/legacy/vm2.mod
new file mode 100644
index 0000000000000000000000000000000000000000..a241b9290d3fe52532b53a3954fb2b29ea104069
--- /dev/null
+++ b/tests/trend-component-and-var-models/legacy/vm2.mod
@@ -0,0 +1,119 @@
+var y4 y3 y2 y1;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112 A113 A114
+           A121 A122 A123 A124
+           A131 A132 A133 A134
+           A141 A142 A143 A144
+           A211 A212 A213 A214
+           A221 A222 A223 A224
+           A231 A232 A233 A234
+           A241 A242 A243 A244
+           A311 A312 A313 A314
+           A321 A322 A323 A324
+           A331 A332 A333 A334
+           A341 A342 A343 A344 ;
+
+A1 = randn(4);
+A2 = randn(4);
+A3 = randn(4);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A113 = A1(1,3);
+A114 = A1(1,4);
+A121 = A1(2,1);
+A122 = A1(2,2);
+A123 = A1(2,3);
+A124 = A1(2,4);
+A131 = A1(3,1);
+A132 = A1(3,2);
+A133 = A1(3,3);
+A134 = A1(3,4);
+A141 = A1(4,1);
+A142 = A1(4,2);
+A143 = A1(4,3);
+A144 = A1(4,4);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A213 = A2(1,3);
+A214 = A2(1,4);
+A221 = A2(2,1);
+A222 = A2(2,2);
+A223 = A2(2,3);
+A224 = A2(2,4);
+A231 = A2(3,1);
+A232 = A2(3,2);
+A233 = A2(3,3);
+A234 = A2(3,4);
+A241 = A2(4,1);
+A242 = A2(4,2);
+A243 = A2(4,3);
+A244 = A2(4,4);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A313 = A3(1,3);
+A314 = A3(1,4);
+A321 = A3(2,1);
+A322 = A3(2,2);
+A323 = A3(2,3);
+A324 = A3(2,4);
+A331 = A3(3,1);
+A332 = A3(3,2);
+A333 = A3(3,3);
+A334 = A3(3,4);
+A341 = A3(4,1);
+A342 = A3(4,2);
+A343 = A3(4,3);
+A344 = A3(4,4);
+
+var_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+y1 = A111*y1(-1) + A112*y2(-1) + A113*y3(-1) + A114*y4(-1) +
+     A211*y1(-2) + A212*y2(-2) + A213*y3(-2) + A214*y4(-2) +
+     A311*y1(-3) + A312*y2(-3) + A313*y3(-3) + A314*y4(-3) + e1; 
+
+[name='eq:y2']
+y2 = A121*y1(-1) + A122*y2(-1) + A123*y3(-1) + A124*y4(-1) +
+     A221*y1(-2) + A222*y2(-2) + A223*y3(-2) + A224*y4(-2) +
+     A321*y1(-3) + A322*y2(-3) + A323*y3(-3) + A324*y4(-3) + e2; 
+
+[name='eq:y3']
+y3 = A131*y1(-1) + A132*y2(-1) + A133*y3(-1) + A134*y4(-1) +
+     A231*y1(-2) + A232*y2(-2) + A233*y3(-2) + A234*y4(-2) +
+     A331*y1(-3) + A332*y2(-3) + A333*y3(-3) + A334*y4(-3) + e3; 
+
+[name='eq:y4']
+y4 = A141*y1(-1) + A142*y2(-1) + A143*y3(-1) + A144*y4(-1) +
+     A241*y1(-2) + A242*y2(-2) + A243*y3(-2) + A244*y4(-2) +
+     A341*y1(-3) + A342*y2(-3) + A343*y3(-3) + A344*y4(-3) + e4;
+
+end;
+
+get_companion_matrix_legacy('toto');
+
+if max(max(abs(oo_.var.toto.ar(:,:,1)-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(oo_.var.toto.ar(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(oo_.var.toto.ar(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
+
+CompanionMatrix = [A1, A2, A3;
+                   eye(4), zeros(4, 8);
+                   zeros(4), eye(4), zeros(4)];
+
+if max(max(abs(CompanionMatrix-oo_.var.toto.CompanionMatrix)))>1e-12
+   error('Companion matrix is wrong.')
+end
\ No newline at end of file
diff --git a/tests/trend-component-and-var-models/legacy/vm3.mod b/tests/trend-component-and-var-models/legacy/vm3.mod
new file mode 100644
index 0000000000000000000000000000000000000000..0585f78a9d921736035f20588dc7e6d03c361a3a
--- /dev/null
+++ b/tests/trend-component-and-var-models/legacy/vm3.mod
@@ -0,0 +1,119 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112 A113 A114
+           A121 A122 A123 A124
+           A131 A132 A133 A134
+           A141 A142 A143 A144
+           A211 A212 A213 A214
+           A221 A222 A223 A224
+           A231 A232 A233 A234
+           A241 A242 A243 A244
+           A311 A312 A313 A314
+           A321 A322 A323 A324
+           A331 A332 A333 A334
+           A341 A342 A343 A344 ;
+
+A1 = randn(4);
+A2 = randn(4);
+A3 = randn(4);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A113 = A1(1,3);
+A114 = A1(1,4);
+A121 = A1(2,1);
+A122 = A1(2,2);
+A123 = A1(2,3);
+A124 = A1(2,4);
+A131 = A1(3,1);
+A132 = A1(3,2);
+A133 = A1(3,3);
+A134 = A1(3,4);
+A141 = A1(4,1);
+A142 = A1(4,2);
+A143 = A1(4,3);
+A144 = A1(4,4);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A213 = A2(1,3);
+A214 = A2(1,4);
+A221 = A2(2,1);
+A222 = A2(2,2);
+A223 = A2(2,3);
+A224 = A2(2,4);
+A231 = A2(3,1);
+A232 = A2(3,2);
+A233 = A2(3,3);
+A234 = A2(3,4);
+A241 = A2(4,1);
+A242 = A2(4,2);
+A243 = A2(4,3);
+A244 = A2(4,4);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A313 = A3(1,3);
+A314 = A3(1,4);
+A321 = A3(2,1);
+A322 = A3(2,2);
+A323 = A3(2,3);
+A324 = A3(2,4);
+A331 = A3(3,1);
+A332 = A3(3,2);
+A333 = A3(3,3);
+A334 = A3(3,4);
+A341 = A3(4,1);
+A342 = A3(4,2);
+A343 = A3(4,3);
+A344 = A3(4,4);
+
+var_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y4']
+y4 = A141*y1(-1) + A142*y2(-1) + A143*y3(-1) + A144*y4(-1) +
+     A241*y1(-2) + A242*y2(-2) + A243*y3(-2) + A244*y4(-2) +
+     A341*y1(-3) + A342*y2(-3) + A343*y3(-3) + A344*y4(-3) + e4;
+
+[name='eq:y3']
+y3 = A131*y1(-1) + A132*y2(-1) + A133*y3(-1) + A134*y4(-1) +
+     A231*y1(-2) + A232*y2(-2) + A233*y3(-2) + A234*y4(-2) +
+     A331*y1(-3) + A332*y2(-3) + A333*y3(-3) + A334*y4(-3) + e3; 
+
+[name='eq:y2']
+y2 = A121*y1(-1) + A122*y2(-1) + A123*y3(-1) + A124*y4(-1) +
+     A221*y1(-2) + A222*y2(-2) + A223*y3(-2) + A224*y4(-2) +
+     A321*y1(-3) + A322*y2(-3) + A323*y3(-3) + A324*y4(-3) + e2; 
+
+[name='eq:y1']
+y1 = A111*y1(-1) + A112*y2(-1) + A113*y3(-1) + A114*y4(-1) +
+     A211*y1(-2) + A212*y2(-2) + A213*y3(-2) + A214*y4(-2) +
+     A311*y1(-3) + A312*y2(-3) + A313*y3(-3) + A314*y4(-3) + e1; 
+
+end;
+
+get_companion_matrix_legacy('toto');
+
+if max(max(abs(oo_.var.toto.ar(:,:,1)-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(oo_.var.toto.ar(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(oo_.var.toto.ar(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
+
+CompanionMatrix = [A1, A2, A3;
+                   eye(4), zeros(4, 8);
+                   zeros(4), eye(4), zeros(4)];
+
+if max(max(abs(CompanionMatrix-oo_.var.toto.CompanionMatrix)))>1e-12
+   error('Companion matrix is wrong.')
+end
\ No newline at end of file
diff --git a/tests/trend-component-and-var-models/tcm1.mod b/tests/trend-component-and-var-models/tcm1.mod
new file mode 100644
index 0000000000000000000000000000000000000000..1739087489689b9763f87e6a9aaee912efbc9fd2
--- /dev/null
+++ b/tests/trend-component-and-var-models/tcm1.mod
@@ -0,0 +1,84 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112
+           A121 A122
+           A211 A212
+           A221 A222
+           A311 A312
+           A321 A322
+           B11 B12 B21 B22;
+
+A1 = randn(2);
+A2 = randn(2);
+A3 = randn(2);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A121 = A1(2,1);
+A122 = A1(2,2);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A221 = A2(2,1);
+A222 = A2(2,2);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A321 = A3(2,1);
+A322 = A3(2,2);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+trend_component_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4'], targets=['eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+end;
+
+[EC, A0star, AR, T] = get_companion_matrix('toto');
+
+if max(max(abs(EC-B)))>1e-12
+   error('Error component matrix is wrong.')
+end
+
+A1fake = AR(:,:,1);
+
+if max(max(abs(A1fake-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
diff --git a/tests/trend-component-and-var-models/tcm10.mod b/tests/trend-component-and-var-models/tcm10.mod
new file mode 100644
index 0000000000000000000000000000000000000000..1a7d9d7a59b85ea84e42cb9c309e368eeb202eb4
--- /dev/null
+++ b/tests/trend-component-and-var-models/tcm10.mod
@@ -0,0 +1,93 @@
+var y1 y2 y3 y4 y5;
+
+varexo e1 e2 e3 e4 e5;
+
+parameters A111 A112
+           A121 A122
+           A211 A212
+           A221 A222
+           A311 A312
+           A321 A322
+           B11 B12 B21 B22;
+
+A1 = randn(2);
+A2 = randn(2);
+A3 = randn(2);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A121 = A1(2,1);
+A122 = A1(2,2);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A221 = A2(2,1);
+A222 = A2(2,2);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A321 = A3(2,1);
+A322 = A3(2,2);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+Bstar = [B11, B12, -B11; B21, B22, -B21];
+
+trend_component_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4', 'eq:y5'], targets=['eq:y3', 'eq:y4', 'eq:y5']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)+y5(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)+y5(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+[name='eq:y5']
+y5 = y5(-1) + e5;
+
+end;
+
+[A0, A0star, AR, T] = get_companion_matrix('toto');
+
+if max(max(abs(A0-B)))>1e-12
+   error('Error component matrix (A0) is wrong.')
+end
+
+if max(max(abs(A0star-Bstar)))>1e-12
+   error('Error component matrix (A0star) is wrong.')
+end
+
+A1fake = AR(:,:,1);
+
+if max(max(abs(A1fake-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
diff --git a/tests/trend-component-and-var-models/tcm11.mod b/tests/trend-component-and-var-models/tcm11.mod
new file mode 100644
index 0000000000000000000000000000000000000000..239b5ad15f05e8dc6ad67f259b386c7d5bf53ba9
--- /dev/null
+++ b/tests/trend-component-and-var-models/tcm11.mod
@@ -0,0 +1,95 @@
+var y1 y2 y3 y4 y5;
+
+varexo e1 e2 e3 e4 e5;
+
+parameters A111 A112
+           A121 A122
+           A211 A212
+           A221 A222
+           A311 A312
+           A321 A322
+           B11 B12 B21 B22 lr;
+
+A1 = randn(2);
+A2 = randn(2);
+A3 = randn(2);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A121 = A1(2,1);
+A122 = A1(2,2);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A221 = A2(2,1);
+A222 = A2(2,2);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A321 = A3(2,1);
+A322 = A3(2,2);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+lr = .1;
+
+Bstar = [B11, B12, -lr*B11; B21, B22, -lr*B21];
+
+trend_component_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4', 'eq:y5'], targets=['eq:y3', 'eq:y4', 'eq:y5']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)+lr*y5(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)+lr*y5(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+[name='eq:y5']
+y5 = y5(-1) + e5;
+
+end;
+
+[A0, A0star, AR, T] = get_companion_matrix('toto');
+
+if max(max(abs(A0-B)))>1e-12
+   error('Error component matrix (A0) is wrong.')
+end
+
+if max(max(abs(A0star-Bstar)))>1e-12
+   error('Error component matrix (A0star) is wrong.')
+end
+
+A1fake = AR(:,:,1);
+
+if max(max(abs(A1fake-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
diff --git a/tests/trend-component-and-var-models/tcm12.mod b/tests/trend-component-and-var-models/tcm12.mod
new file mode 100644
index 0000000000000000000000000000000000000000..61a0830e1435193951940e62d132c3d17e05e736
--- /dev/null
+++ b/tests/trend-component-and-var-models/tcm12.mod
@@ -0,0 +1,95 @@
+var y1 y2 y3 y4 y5;
+
+varexo e1 e2 e3 e4 e5;
+
+parameters A111 A112
+           A121 A122
+           A211 A212
+           A221 A222
+           A311 A312
+           A321 A322
+           B11 B12 B21 B22 lr;
+
+A1 = randn(2);
+A2 = randn(2);
+A3 = randn(2);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A121 = A1(2,1);
+A122 = A1(2,2);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A221 = A2(2,1);
+A222 = A2(2,2);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A321 = A3(2,1);
+A322 = A3(2,2);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+lr = .1;
+
+Bstar = [B11, B12, -lr*.2*B11; B21, B22, -lr*.2*B21];
+
+trend_component_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4', 'eq:y5'], targets=['eq:y3', 'eq:y4', 'eq:y5']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)+lr*.2*y5(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)+lr*.2*y5(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+[name='eq:y5']
+y5 = y5(-1) + e5;
+
+end;
+
+[A0, A0star, AR, T] = get_companion_matrix('toto');
+
+if max(max(abs(A0-B)))>1e-12
+   error('Error component matrix (A0) is wrong.')
+end
+
+if max(max(abs(A0star-Bstar)))>1e-12
+   error('Error component matrix (A0star) is wrong.')
+end
+
+A1fake = AR(:,:,1);
+
+if max(max(abs(A1fake-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
diff --git a/tests/trend-component-and-var-models/tcm2.mod b/tests/trend-component-and-var-models/tcm2.mod
new file mode 100644
index 0000000000000000000000000000000000000000..a9732061115595084c235162e54172554a163638
--- /dev/null
+++ b/tests/trend-component-and-var-models/tcm2.mod
@@ -0,0 +1,84 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112
+           A121 A122
+           A211 A212
+           A221 A222
+           A311 A312
+           A321 A322
+           B11 B12 B21 B22;
+
+A1 = randn(2);
+A2 = randn(2);
+A3 = randn(2);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A121 = A1(2,1);
+A122 = A1(2,2);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A221 = A2(2,1);
+A222 = A2(2,2);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A321 = A3(2,1);
+A322 = A3(2,2);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+trend_component_model(model_name=toto, eqtags=['eq:y1', 'eq:y4', 'eq:y2', 'eq:y3'], targets=['eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+end;
+
+[EC, A0star, AR, T] = get_companion_matrix('toto');
+
+if max(max(abs(EC-B)))>1e-12
+   error('Error component matrix is wrong.')
+end
+
+A1fake = AR(:,:,1);
+
+if max(max(abs(A1fake-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
diff --git a/tests/trend-component-and-var-models/tcm3.mod b/tests/trend-component-and-var-models/tcm3.mod
new file mode 100644
index 0000000000000000000000000000000000000000..1739087489689b9763f87e6a9aaee912efbc9fd2
--- /dev/null
+++ b/tests/trend-component-and-var-models/tcm3.mod
@@ -0,0 +1,84 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112
+           A121 A122
+           A211 A212
+           A221 A222
+           A311 A312
+           A321 A322
+           B11 B12 B21 B22;
+
+A1 = randn(2);
+A2 = randn(2);
+A3 = randn(2);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A121 = A1(2,1);
+A122 = A1(2,2);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A221 = A2(2,1);
+A222 = A2(2,2);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A321 = A3(2,1);
+A322 = A3(2,2);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+trend_component_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4'], targets=['eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+end;
+
+[EC, A0star, AR, T] = get_companion_matrix('toto');
+
+if max(max(abs(EC-B)))>1e-12
+   error('Error component matrix is wrong.')
+end
+
+A1fake = AR(:,:,1);
+
+if max(max(abs(A1fake-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
diff --git a/tests/trend-component-and-var-models/tcm4.mod b/tests/trend-component-and-var-models/tcm4.mod
new file mode 100644
index 0000000000000000000000000000000000000000..1a24d5f5b9948fbb327695abbc8dbdce4371ce54
--- /dev/null
+++ b/tests/trend-component-and-var-models/tcm4.mod
@@ -0,0 +1,85 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112
+           A121 A122
+           A211 A212
+           A221 A222
+           A311 A312
+           A321 A322
+           B11 B12 B21 B22;
+
+A1 = randn(2);
+A2 = randn(2);
+A3 = randn(2);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A121 = A1(2,1);
+A122 = A1(2,2);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A221 = A2(2,1);
+A222 = A2(2,2);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A321 = A3(2,1);
+A322 = A3(2,2);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+trend_component_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4'], targets=['eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+end;
+
+[EC, A0star, AR, T] = get_companion_matrix('toto');
+
+if max(max(abs(EC-B)))>1e-12
+   error('Error component matrix is wrong.')
+end
+
+A1fake = AR(:,:,1);
+
+if max(max(abs(A1fake-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
diff --git a/tests/trend-component-and-var-models/tcm5.mod b/tests/trend-component-and-var-models/tcm5.mod
new file mode 100644
index 0000000000000000000000000000000000000000..b645a47ac070a72890c14e5d6eff12f9e568c099
--- /dev/null
+++ b/tests/trend-component-and-var-models/tcm5.mod
@@ -0,0 +1,85 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112
+           A121 A122
+           A211 A212
+           A221 A222
+           A311 A312
+           A321 A322
+           B11 B12 B21 B22;
+
+A1 = randn(2);
+A2 = randn(2);
+A3 = randn(2);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A121 = A1(2,1);
+A122 = A1(2,2);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A221 = A2(2,1);
+A222 = A2(2,2);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A321 = A3(2,1);
+A322 = A3(2,2);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+trend_component_model(model_name=toto, eqtags=['eq:y4', 'eq:y1', 'eq:y2', 'eq:y3'], targets=['eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+end;
+
+[EC, A0star, AR, T] = get_companion_matrix('toto');
+
+if max(max(abs(EC-B)))>1e-12
+   error('Error component matrix is wrong.')
+end
+
+A1fake = AR(:,:,1);
+
+if max(max(abs(A1fake-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
diff --git a/tests/trend-component-and-var-models/tcm6.mod b/tests/trend-component-and-var-models/tcm6.mod
new file mode 100644
index 0000000000000000000000000000000000000000..a44bd6b42b1f495ad231f0622c3ad8818aad1999
--- /dev/null
+++ b/tests/trend-component-and-var-models/tcm6.mod
@@ -0,0 +1,173 @@
+// --+ options: stochastic,json=compute +--
+
+var U2_Q_YED
+    U2_G_YER
+    U2_STN
+    U2_EHIC
+    U2_ESTN
+    U2_G_EYER
+    U2_HH_OCOR
+    U2_HH_COR
+    U2_H_Q_YER400
+    U2_HH_COR1
+    ;
+
+varexo res_U2_Q_YED
+       res_U2_G_YER
+       res_U2_STN
+       res_U2_EHIC
+       res_U2_ESTN
+       res_U2_G_EYER
+       res_U2_HH_OCOR
+       res_U2_H_Q_YER
+       res_ez ;
+
+parameters u2_q_yed_ecm_u2_q_yed_L1
+           u2_q_yed_ecm_u2_stn_L1
+           u2_q_yed_u2_q_yed_L1
+           u2_q_yed_u2_g_yer_L1
+           u2_q_yed_u2_stn_L1
+           u2_g_yer_ecm_u2_q_yed_L1
+           u2_g_yer_ecm_u2_stn_L1
+           u2_g_yer_u2_q_yed_L1
+           u2_g_yer_u2_g_yer_L1
+           u2_g_yer_u2_stn_L1
+           u2_stn_ecm_u2_q_yed_L1
+           u2_stn_ecm_u2_stn_L1
+           u2_stn_u2_q_yed_L1
+           u2_stn_u2_g_yer_L1
+           u2_q_yed_ecm_u2_g_yer_L1
+           u2_g_yer_ecm_u2_g_yer_L1
+           u2_stn_ecm_u2_g_yer_L1
+           u2_hh_ocor_ecm_u2_q_yed_L1
+           u2_hh_ocor_ecm_u2_stn_L1
+           u2_hh_ocor_ecm_u2_g_yer_L1
+           u2_hh_ocor_u2_q_yed_L1
+           u2_hh_ocor_u2_g_yer_L1
+           u2_hh_ocor_u2_stn_L1
+           u2_hh_ocor_ecm_u2_hh_ocor_L1
+           u2_hh_ocor_u2_hh_ocor_L1
+           beta
+           ecm_pac
+           u2_hh_cor_pac_u2_hh_cor_L1 ;
+
+
+beta = 0.98 ;
+ecm_pac = 0.2;
+u2_hh_cor_pac_u2_hh_cor_L1 = 0.4;
+
+model;
+
+[name='U2_Q_YED']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_ecm_u2_g_yer_L1 * (U2_G_YER(-1)- U2_G_EYER(-1))
+                 + u2_q_yed_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+
+[name='U2_G_YER']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_ecm_u2_g_yer_L1 * (U2_G_YER(-1) - U2_G_EYER(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+
+[name='U2_STN']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_ecm_u2_g_yer_L1   * (U2_G_YER(-1) - U2_G_EYER(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+
+[name='U2_ESTN']
+U2_ESTN        =  U2_ESTN(-1) + res_U2_ESTN                               ;
+
+[name='U2_EHIC']
+U2_EHIC        =  U2_EHIC(-1) + res_U2_EHIC                               ;
+
+[name='U2_G_EYER']
+U2_G_EYER        =  U2_G_EYER(-1) + res_U2_G_EYER                               ;
+
+[name='U2_HH_OCOR']
+diff(diff(log(U2_HH_OCOR))) =  u2_hh_ocor_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_hh_ocor_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_hh_ocor_ecm_u2_g_yer_L1   * (U2_G_YER(-1) - U2_G_EYER(-1))
+                 + u2_hh_ocor_ecm_u2_hh_ocor_L1    * (diff(log(U2_HH_OCOR(-1))) - U2_H_Q_YER400(-1))
+                 + u2_hh_ocor_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_hh_ocor_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + u2_hh_ocor_u2_stn_L1         * diff(U2_STN(-1))
+                 + u2_hh_ocor_u2_hh_ocor_L1        * diff(diff(log(U2_HH_OCOR(-1))))
+                 + res_U2_HH_OCOR                                        ;
+
+[name='U2_H_Q_YER400']
+U2_H_Q_YER400 = U2_H_Q_YER400(-1) + res_U2_H_Q_YER;
+
+[name='zpac']
+diff(log(U2_HH_COR)) = ecm_pac*(log(U2_HH_OCOR(-1))-log(U2_HH_COR(-1))) +
+                  u2_hh_cor_pac_u2_hh_cor_L1*diff(log(U2_HH_COR(-1))) +
+                  pac_expectation(pacman)   +
+                  res_ez;
+
+[name='zpac1']
+diff(log(U2_HH_COR1)) = ecm_pac*(log(U2_HH_OCOR(-1))-log(U2_HH_COR1(-1))) +
+                  u2_hh_cor_pac_u2_hh_cor_L1*diff(log(U2_HH_COR1(-1))) +
+                  pac_expectation(pacman1) +
+                  res_ez;
+
+end;
+
+// Random calibration for the TREND_COMPONENT_MODEL's parameters.
+M_.params(1:25) = randn(25, 1);
+params = M_.params;
+
+trend_component_model(model_name=toto, eqtags=['U2_Q_YED', 'U2_G_YER', 'U2_STN', 'U2_EHIC', 'U2_G_EYER', 'U2_ESTN', 'U2_HH_OCOR', 'U2_H_Q_YER400'], targets=['U2_EHIC', 'U2_G_EYER', 'U2_ESTN', 'U2_H_Q_YER400']);
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman, growth = U2_H_Q_YER400);
+pac.initialize('pacman');
+C0 = oo_.trend_component.toto.CompanionMatrix;
+
+trend_component_model(model_name=titi, eqtags=['U2_Q_YED', 'U2_G_YER', 'U2_STN', 'U2_EHIC', 'U2_G_EYER', 'U2_ESTN', 'U2_HH_OCOR', 'U2_H_Q_YER400'], targets=['U2_G_EYER', 'U2_H_Q_YER400', 'U2_ESTN', 'U2_EHIC']);
+pac_model(auxiliary_model_name=titi, discount=beta, model_name=pacman1, growth = U2_H_Q_YER400);
+pac.initialize('pacman1');
+C1 = oo_.trend_component.titi.CompanionMatrix;
+
+[AR0, A00, A00star] = feval([M_.fname '.trend_component_ar_a0'], 'toto', M_.params);
+[AR1, A01, A01star] = feval([M_.fname '.trend_component_ar_a0'], 'titi', M_.params);
+
+save('tcm6_data.mat', 'C0', 'AR0', 'A00', 'A00star', 'C1', 'AR1', 'A01', 'A01star', 'params');
+
+if sum(sum(abs(AR0-AR1))) ~= 0
+    error('Problem with AR matrices')
+end
+
+if sum(sum(abs(A00-A01))) ~= 0
+    error('Problem with A0 matrices')
+end
+
+if sum(sum(abs(A00star-A01star(:,[4,1,3,2])))) ~= 0
+    error('Problem with A0star matrices')
+end
+
+ar = zeros(4, 4, 1);
+ar(1,:) = [M_.params(strcmp(M_.param_names, 'u2_q_yed_u2_q_yed_L1')),   M_.params(strcmp(M_.param_names, 'u2_q_yed_u2_g_yer_L1')),   M_.params(strcmp(M_.param_names, 'u2_q_yed_u2_stn_L1')),   0];
+ar(2,:) = [M_.params(strcmp(M_.param_names, 'u2_g_yer_u2_q_yed_L1')),   M_.params(strcmp(M_.param_names, 'u2_g_yer_u2_g_yer_L1')),   M_.params(strcmp(M_.param_names, 'u2_g_yer_u2_stn_L1')),   0];
+ar(3,:) = [M_.params(strcmp(M_.param_names, 'u2_stn_u2_q_yed_L1')),     M_.params(strcmp(M_.param_names, 'u2_stn_u2_g_yer_L1')),     0,                                                         0];
+ar(4,:) = [M_.params(strcmp(M_.param_names, 'u2_hh_ocor_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_u2_g_yer_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_u2_stn_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_u2_hh_ocor_L1'))];
+
+if sum(sum(abs(AR0-ar))) ~= 0
+    error('Problem with AR matrix')
+end
+
+a0 = zeros(4, 4, 1);
+a0(1,:) = [M_.params(strcmp(M_.param_names, 'u2_q_yed_ecm_u2_q_yed_L1')),   M_.params(strcmp(M_.param_names, 'u2_q_yed_ecm_u2_g_yer_L1')),   M_.params(strcmp(M_.param_names, 'u2_q_yed_ecm_u2_stn_L1')),   0];
+a0(2,:) = [M_.params(strcmp(M_.param_names, 'u2_g_yer_ecm_u2_q_yed_L1')),   M_.params(strcmp(M_.param_names, 'u2_g_yer_ecm_u2_g_yer_L1')),   M_.params(strcmp(M_.param_names, 'u2_g_yer_ecm_u2_stn_L1')),   0];
+a0(3,:) = [M_.params(strcmp(M_.param_names, 'u2_stn_ecm_u2_q_yed_L1')),     M_.params(strcmp(M_.param_names, 'u2_stn_ecm_u2_g_yer_L1')),     M_.params(strcmp(M_.param_names, 'u2_stn_ecm_u2_stn_L1')),     0];
+a0(4,:) = [M_.params(strcmp(M_.param_names, 'u2_hh_ocor_ecm_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_ecm_u2_g_yer_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_ecm_u2_stn_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_ecm_u2_hh_ocor_L1'))];
+
+if sum(sum(abs(A00star-a0))) ~= 0
+    error('Problem with A0star matrix')
+end
diff --git a/tests/trend-component-and-var-models/tcm7.mod b/tests/trend-component-and-var-models/tcm7.mod
new file mode 100644
index 0000000000000000000000000000000000000000..d83815aaec63218ca7df3761b25c5c4c569f8970
--- /dev/null
+++ b/tests/trend-component-and-var-models/tcm7.mod
@@ -0,0 +1,145 @@
+// --+ options: stochastic,json=compute +--
+
+var U2_Q_YED
+    U2_G_YER
+    U2_STN
+    U2_EHIC
+    U2_ESTN
+    U2_G_EYER
+    U2_HH_OCOR
+    U2_HH_COR
+    U2_H_Q_YER400
+    U2_HH_COR1 ;
+
+varexo res_U2_Q_YED
+       res_U2_G_YER
+       res_U2_STN
+       res_U2_EHIC
+       res_U2_ESTN
+       res_U2_G_EYER
+       res_U2_HH_OCOR
+       res_U2_H_Q_YER
+       res_ez ;
+
+parameters u2_q_yed_ecm_u2_q_yed_L1
+           u2_q_yed_ecm_u2_stn_L1
+           u2_q_yed_u2_q_yed_L1
+           u2_q_yed_u2_g_yer_L1
+           u2_q_yed_u2_stn_L1
+           u2_g_yer_ecm_u2_q_yed_L1
+           u2_g_yer_ecm_u2_stn_L1
+           u2_g_yer_u2_q_yed_L1
+           u2_g_yer_u2_g_yer_L1
+           u2_g_yer_u2_stn_L1
+           u2_stn_ecm_u2_q_yed_L1
+           u2_stn_ecm_u2_stn_L1
+           u2_stn_u2_q_yed_L1
+           u2_stn_u2_g_yer_L1
+           u2_q_yed_ecm_u2_g_yer_L1
+           u2_g_yer_ecm_u2_g_yer_L1
+           u2_stn_ecm_u2_g_yer_L1
+           u2_hh_ocor_ecm_u2_q_yed_L1
+           u2_hh_ocor_ecm_u2_stn_L1
+           u2_hh_ocor_ecm_u2_g_yer_L1
+           u2_hh_ocor_u2_q_yed_L1
+           u2_hh_ocor_u2_g_yer_L1
+           u2_hh_ocor_u2_stn_L1
+           u2_hh_ocor_ecm_u2_hh_ocor_L1
+           u2_hh_ocor_u2_hh_ocor_L1
+           beta
+           ecm_pac
+           u2_hh_cor_pac_u2_hh_cor_L1 ;
+
+
+beta = 0.98 ;
+ecm_pac = 0.2;
+u2_hh_cor_pac_u2_hh_cor_L1 = 0.4;
+
+model;
+
+[name='U2_G_YER']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_ecm_u2_g_yer_L1 * (U2_G_YER(-1) - U2_G_EYER(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+
+
+[name='U2_Q_YED']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_ecm_u2_g_yer_L1 * (U2_G_YER(-1)- U2_G_EYER(-1))
+                 + u2_q_yed_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+
+
+[name='U2_ESTN']
+U2_ESTN        =  U2_ESTN(-1) + res_U2_ESTN                               ;
+
+[name='U2_EHIC']
+U2_EHIC        =  U2_EHIC(-1) + res_U2_EHIC                               ;
+
+[name='U2_G_EYER']
+U2_G_EYER        =  U2_G_EYER(-1) + res_U2_G_EYER                               ;
+
+[name='U2_HH_OCOR']
+diff(diff(log(U2_HH_OCOR))) =  u2_hh_ocor_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_hh_ocor_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_hh_ocor_ecm_u2_g_yer_L1   * (U2_G_YER(-1) - U2_G_EYER(-1))
+                 + u2_hh_ocor_ecm_u2_hh_ocor_L1    * (diff(log(U2_HH_OCOR(-1))) - U2_H_Q_YER400(-1))
+                 + u2_hh_ocor_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_hh_ocor_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + u2_hh_ocor_u2_stn_L1         * diff(U2_STN(-1))
+                 + u2_hh_ocor_u2_hh_ocor_L1        * diff(diff(log(U2_HH_OCOR(-1))))
+                 + res_U2_HH_OCOR                                        ;
+
+[name='U2_H_Q_YER400']
+U2_H_Q_YER400 = U2_H_Q_YER400(-1) + res_U2_H_Q_YER;
+
+[name='U2_STN']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_ecm_u2_g_yer_L1   * (U2_G_YER(-1) - U2_G_EYER(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+
+[name='zpac']
+diff(log(U2_HH_COR)) = ecm_pac*(log(U2_HH_OCOR(-1))-log(U2_HH_COR(-1))) +
+                  u2_hh_cor_pac_u2_hh_cor_L1*diff(log(U2_HH_COR(-1))) +
+                  pac_expectation(pacman)   +
+                  res_ez;
+
+[name='zpac1']
+diff(log(U2_HH_COR1)) = ecm_pac*(log(U2_HH_OCOR(-1))-log(U2_HH_COR1(-1))) +
+                  u2_hh_cor_pac_u2_hh_cor_L1*diff(log(U2_HH_COR1(-1))) +
+                  pac_expectation(pacman1) +
+                  res_ez;
+end;
+
+// Use the same calibration as in tcm6.mod.
+tcm6 = load('tcm6_data.mat');
+M_.params = tcm6.params;
+
+
+trend_component_model(model_name=toto, eqtags=['U2_Q_YED', 'U2_G_YER', 'U2_STN', 'U2_EHIC', 'U2_G_EYER', 'U2_ESTN', 'U2_HH_OCOR', 'U2_H_Q_YER400'], targets=['U2_EHIC', 'U2_G_EYER', 'U2_ESTN', 'U2_H_Q_YER400']);
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman, growth = U2_H_Q_YER400);
+pac.initialize('pacman');
+C0 = oo_.trend_component.toto.CompanionMatrix;
+
+trend_component_model(model_name=titi, eqtags=['U2_Q_YED', 'U2_G_YER', 'U2_STN', 'U2_EHIC', 'U2_G_EYER', 'U2_ESTN', 'U2_HH_OCOR', 'U2_H_Q_YER400'], targets=['U2_G_EYER', 'U2_H_Q_YER400', 'U2_ESTN', 'U2_EHIC']);
+pac_model(auxiliary_model_name=titi, discount=beta, model_name=pacman1, growth = U2_H_Q_YER400);
+pac.initialize('pacman1');
+C1 = oo_.trend_component.titi.CompanionMatrix;
+
+if any(abs(C0(:)-tcm6.C0(:)))>1e-12
+   error('Companion matrix is not independent of the ordering of the equations.')
+end
+
+if any(abs(C1(:)-tcm6.C1(:)))>1e-12
+   error('Companion matrix is not independent of the ordering of the equations.')
+end
diff --git a/tests/trend-component-and-var-models/tcm8.mod b/tests/trend-component-and-var-models/tcm8.mod
new file mode 100644
index 0000000000000000000000000000000000000000..7269eb07e8778cebbea8716c19a1c4fcc665f573
--- /dev/null
+++ b/tests/trend-component-and-var-models/tcm8.mod
@@ -0,0 +1,230 @@
+// --+ options: stochastic,json=compute +--
+
+var U2_Q_YED
+    U2_G_YER
+    U2_STN
+    U2_EHIC
+    U2_ESTN
+    U2_G_EYER
+    U2_HH_OCOR
+    U2_HH_COR
+    U2_H_Q_YER400
+    U2_HH_COR1 ;
+
+varexo res_U2_Q_YED
+       res_U2_G_YER
+       res_U2_STN
+       res_U2_EHIC
+       res_U2_ESTN
+       res_U2_HH_OCOR
+       res_U2_H_Q_YER
+       res_ez ;
+
+parameters u2_q_yed_ecm_u2_q_yed_L1
+           u2_q_yed_ecm_u2_stn_L1
+           u2_q_yed_u2_q_yed_L1
+           u2_q_yed_u2_g_yer_L1
+           u2_q_yed_u2_stn_L1
+           u2_g_yer_ecm_u2_q_yed_L1
+           u2_g_yer_ecm_u2_stn_L1
+           u2_g_yer_u2_q_yed_L1
+           u2_g_yer_u2_g_yer_L1
+           u2_g_yer_u2_stn_L1
+           u2_stn_ecm_u2_q_yed_L1
+           u2_stn_ecm_u2_stn_L1
+           u2_stn_u2_q_yed_L1
+           u2_stn_u2_g_yer_L1
+           u2_q_yed_ecm_u2_g_yer_L1
+           u2_g_yer_ecm_u2_g_yer_L1
+           u2_stn_ecm_u2_g_yer_L1
+           u2_hh_ocor_ecm_u2_q_yed_L1
+           u2_hh_ocor_ecm_u2_stn_L1
+           u2_hh_ocor_ecm_u2_g_yer_L1
+           u2_hh_ocor_u2_q_yed_L1
+           u2_hh_ocor_u2_g_yer_L1
+           u2_hh_ocor_u2_stn_L1
+           u2_hh_ocor_ecm_u2_hh_ocor_L1
+           u2_hh_ocor_u2_hh_ocor_L1
+           beta
+           ecm_pac
+           u2_hh_cor_pac_u2_hh_cor_L1 ;
+
+
+beta = 0.98 ;
+ecm_pac = 0.2;
+u2_hh_cor_pac_u2_hh_cor_L1 = 0.4;
+
+model;
+
+[name='U2_G_YER']
+diff(U2_G_YER) =   u2_g_yer_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_g_yer_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_g_yer_ecm_u2_g_yer_L1 * (U2_G_YER(-1) - U2_G_EYER(-1))
+                 + u2_g_yer_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_g_yer_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_g_yer_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_G_YER                                           ;
+
+
+[name='U2_Q_YED']
+diff(U2_Q_YED) =   u2_q_yed_ecm_u2_q_yed_L1 * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_q_yed_ecm_u2_stn_L1   * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_q_yed_ecm_u2_g_yer_L1 * (U2_G_YER(-1)- U2_G_EYER(-1))
+                 + u2_q_yed_u2_q_yed_L1     * diff(U2_Q_YED(-1))
+                 + u2_q_yed_u2_g_yer_L1     * diff(U2_G_YER(-1))
+                 + u2_q_yed_u2_stn_L1       * diff(U2_STN(-1))
+                 + res_U2_Q_YED                                           ;
+
+
+[name='U2_ESTN']
+U2_ESTN        =  U2_ESTN(-1) + res_U2_ESTN                               ;
+
+[name='U2_EHIC']
+U2_EHIC        =  U2_EHIC(-1) + res_U2_EHIC                               ;
+
+[name='U2_G_EYER']
+U2_G_EYER        =  0;
+
+[name='U2_HH_OCOR']
+diff(diff(log(U2_HH_OCOR))) =  u2_hh_ocor_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_hh_ocor_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_hh_ocor_ecm_u2_g_yer_L1   * (U2_G_YER(-1) - U2_G_EYER(-1))
+                 + u2_hh_ocor_ecm_u2_hh_ocor_L1    * (diff(log(U2_HH_OCOR(-1))) - U2_H_Q_YER400(-1))
+                 + u2_hh_ocor_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_hh_ocor_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + u2_hh_ocor_u2_stn_L1         * diff(U2_STN(-1))
+                 + u2_hh_ocor_u2_hh_ocor_L1        * diff(diff(log(U2_HH_OCOR(-1))))
+                 + res_U2_HH_OCOR                                        ;
+
+[name='U2_H_Q_YER400']
+U2_H_Q_YER400 = U2_H_Q_YER400(-1) + res_U2_H_Q_YER;
+
+[name='U2_STN']
+diff(U2_STN)   =   u2_stn_ecm_u2_q_yed_L1   * (U2_Q_YED(-1) - U2_EHIC(-1))
+                 + u2_stn_ecm_u2_stn_L1     * (U2_STN(-1)   - U2_ESTN(-1))
+                 + u2_stn_ecm_u2_g_yer_L1   * (U2_G_YER(-1) - U2_G_EYER(-1))
+                 + u2_stn_u2_q_yed_L1       * diff(U2_Q_YED(-1))
+                 + u2_stn_u2_g_yer_L1       * diff(U2_G_YER(-1))
+                 + res_U2_STN                                             ;
+
+[name='zpac']
+diff(log(U2_HH_COR)) = ecm_pac*(log(U2_HH_OCOR(-1))-log(U2_HH_COR(-1))) +
+                  u2_hh_cor_pac_u2_hh_cor_L1*diff(log(U2_HH_COR(-1))) +
+                  pac_expectation(pacman)   +
+                  res_ez;
+
+[name='zpac1']
+diff(log(U2_HH_COR1)) = ecm_pac*(log(U2_HH_OCOR(-1))-log(U2_HH_COR1(-1))) +
+                  u2_hh_cor_pac_u2_hh_cor_L1*diff(log(U2_HH_COR1(-1))) +
+                  pac_expectation(pacman1)   +
+                  res_ez;
+end;
+
+// Use the same calibration as in tcm6.mod.
+tcm6 = load('tcm6_data.mat');
+M_.params = tcm6.params;
+
+trend_component_model(model_name=toto, eqtags=['U2_Q_YED', 'U2_G_YER', 'U2_STN', 'U2_EHIC', 'U2_ESTN', 'U2_HH_OCOR', 'U2_H_Q_YER400'], targets=['U2_EHIC', 'U2_ESTN', 'U2_H_Q_YER400']);
+trend_component_model(model_name=titi, eqtags=['U2_Q_YED', 'U2_G_YER', 'U2_STN', 'U2_EHIC', 'U2_ESTN', 'U2_HH_OCOR', 'U2_H_Q_YER400'], targets=['U2_H_Q_YER400', 'U2_ESTN', 'U2_EHIC']);
+
+% toto
+AR  = zeros(4,4,1);
+A0  = zeros(4,4,1);
+A0s = zeros(4,3,1);
+
+AR(1,:) = [M_.params(strcmp(M_.param_names, 'u2_q_yed_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_q_yed_u2_g_yer_L1')), M_.params(strcmp(M_.param_names, 'u2_q_yed_u2_stn_L1')), 0];
+AR(2,:) = [M_.params(strcmp(M_.param_names, 'u2_g_yer_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_g_yer_u2_g_yer_L1')), M_.params(strcmp(M_.param_names, 'u2_g_yer_u2_stn_L1')), 0];
+AR(3,:) = [M_.params(strcmp(M_.param_names, 'u2_stn_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_stn_u2_g_yer_L1')), 0, 0];
+AR(4,:) = [M_.params(strcmp(M_.param_names, 'u2_hh_ocor_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_u2_g_yer_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_u2_stn_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_u2_hh_ocor_L1'))];
+
+A0(1,:) = [M_.params(strcmp(M_.param_names, 'u2_q_yed_ecm_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_q_yed_ecm_u2_g_yer_L1')), M_.params(strcmp(M_.param_names, 'u2_q_yed_ecm_u2_stn_L1')), 0];
+A0(2,:) = [M_.params(strcmp(M_.param_names, 'u2_g_yer_ecm_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_g_yer_ecm_u2_g_yer_L1')), M_.params(strcmp(M_.param_names, 'u2_g_yer_ecm_u2_stn_L1')), 0];
+A0(3,:) = [M_.params(strcmp(M_.param_names, 'u2_stn_ecm_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_stn_ecm_u2_g_yer_L1')), M_.params(strcmp(M_.param_names, 'u2_stn_ecm_u2_stn_L1')), 0];
+A0(4,:) = [M_.params(strcmp(M_.param_names, 'u2_hh_ocor_ecm_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_ecm_u2_g_yer_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_ecm_u2_stn_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_ecm_u2_hh_ocor_L1'))];
+
+A0s(1,:) = [M_.params(strcmp(M_.param_names, 'u2_q_yed_ecm_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_q_yed_ecm_u2_stn_L1')), 0];
+A0s(2,:) = [M_.params(strcmp(M_.param_names, 'u2_g_yer_ecm_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_g_yer_ecm_u2_stn_L1')), 0];
+A0s(3,:) = [M_.params(strcmp(M_.param_names, 'u2_stn_ecm_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_stn_ecm_u2_stn_L1')), 0];
+A0s(4,:) = [M_.params(strcmp(M_.param_names, 'u2_hh_ocor_ecm_u2_q_yed_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_ecm_u2_stn_L1')), M_.params(strcmp(M_.param_names, 'u2_hh_ocor_ecm_u2_hh_ocor_L1'))];
+
+[ARt, A0t, A0st] = tcm8.trend_component_ar_a0('toto', M_.params);
+
+if sum(sum(abs(AR-ARt))) ~= 0
+    error('Problem with AR')
+end
+
+if sum(sum(abs(A0-A0t))) ~= 0
+    error('Problem with A0')
+end
+
+if sum(sum(abs(A0s-A0st))) ~= 0
+    error('Problem with A0star')
+end
+
+// Remove column associated to U2_G_EYER
+tcm6.A00star(:,2) = [];
+
+if sum(sum(abs(tcm6.AR0-ARt))) ~= 0
+    error('Problem with AR (relative to tcm6.mod, first model)')
+end
+
+if sum(sum(abs(tcm6.A00-A0t))) ~= 0
+    error('Problem with A0 (relative to tcm6.mod, first model)')
+end
+
+if sum(sum(abs(tcm6.A00star-A0st))) ~= 0
+    error('Problem with A0star (relative to tcm6.mod, first model)')
+end
+
+[ARtt, A0tt, A0stt] = tcm8.trend_component_ar_a0('titi', M_.params);
+
+if sum(sum(abs(AR-ARtt))) ~= 0
+    error('Problem with AR')
+end
+
+if sum(sum(abs(A0-A0tt))) ~= 0
+    error('Problem with A0')
+end
+
+if sum(sum(abs(A0s-A0stt(:,[3,2,1])))) ~= 0
+    error('Problem with A0star')
+end
+
+// Remove column associated to U2_G_EYER
+tcm6.A01star(:,1) = [];
+
+if sum(sum(abs(tcm6.AR1-ARtt))) ~= 0
+    error('Problem with AR (relative to tcm6.mod, second model)')
+end
+
+if sum(sum(abs(tcm6.A01-A0tt))) ~= 0
+    error('Problem with A0 (relative to tcm6.mod, second model)')
+end
+
+if sum(sum(abs(tcm6.A01star-A0stt))) ~= 0
+    error('Problem with A0star (relative to tcm6.mod, second model)')
+end
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman, growth = U2_H_Q_YER400);
+pac.initialize('pacman');
+C0 = oo_.trend_component.toto.CompanionMatrix;
+
+pac_model(auxiliary_model_name=titi, discount=beta, model_name=pacman1, growth = U2_H_Q_YER400);
+pac.initialize('pacman1');
+C1 = oo_.trend_component.titi.CompanionMatrix;
+
+// Remove U2_G_EYER (columns and rows)
+tcm6.C0(:,[5,13]) = [];
+tcm6.C0([5,13],:) = [];
+
+if any(abs(C0(:)-tcm6.C0(:)))>1e-12
+   error('Companion matrix is not independent of the ordering of the equations, first model.')
+end
+
+// Remove U2_G_EYER (columns and rows)
+tcm6.C1(:,[5,13]) = [];
+tcm6.C1([5,13],:) = [];
+
+if any(abs(C1(:)-tcm6.C1(:)))>1e-12
+   error('Companion matrix is not independent of the ordering of the equations, second model.')
+end
diff --git a/tests/trend-component-and-var-models/tcm9.mod b/tests/trend-component-and-var-models/tcm9.mod
new file mode 100644
index 0000000000000000000000000000000000000000..705f0f711b462fb4fcbd27c7e3344ab7deeea096
--- /dev/null
+++ b/tests/trend-component-and-var-models/tcm9.mod
@@ -0,0 +1,90 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112
+           A121 A122
+           A211 A212
+           A221 A222
+           A311 A312
+           A321 A322
+           B11 B12 B21 B22;
+
+A1 = randn(2);
+A2 = randn(2);
+A3 = randn(2);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A121 = A1(2,1);
+A122 = A1(2,2);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A221 = A2(2,1);
+A222 = A2(2,2);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A321 = A3(2,1);
+A322 = A3(2,2);
+
+B = rand(2);
+B(1,1) = -B(1,1);
+B(2,2) = -B(2,2);
+
+B11 = B(1,1);
+B12 = B(1,2);
+B21 = B(2,1);
+B22 = B(2,2);
+
+Bstar = [B11, B12-B11; B21, B22];
+
+trend_component_model(model_name=toto, eqtags=['eq:y1', 'eq:y4', 'eq:y2', 'eq:y3'], targets=['eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+diff(y1) = B11*(y1(-1)-y3(-1)+y4(-1)) + B12*(y2(-1)-y4(-1)) + 
+     A111*diff(y1(-1)) + A112*diff(y2(-1)) +
+     A211*diff(y1(-2)) + A212*diff(y2(-2)) +
+     A311*diff(y1(-3)) + A312*diff(y2(-3)) + e1; 
+
+
+[name='eq:y2']
+diff(y2) = B21*(y1(-1)-y3(-1)) + B22*(y2(-1)-y4(-1)) +
+     A121*diff(y1(-1)) + A122*diff(y2(-1)) +
+     A221*diff(y1(-2)) + A222*diff(y2(-2)) +
+     A321*diff(y1(-3)) + A322*diff(y2(-3)) + e2; 
+
+[name='eq:y3']
+y3 = y3(-1) + e3; 
+
+[name='eq:y4']
+y4 = y4(-1) + e4;
+
+end;
+
+[A0, A0star, AR, T] = get_companion_matrix('toto');
+
+if max(max(abs(A0-B)))>1e-12
+   error('Error component matrix (A0) is wrong.')
+end
+
+if max(max(abs(A0star-Bstar)))>1e-12
+   error('Error component matrix (A0star) is wrong.')
+end
+
+A1fake = AR(:,:,1);
+
+if max(max(abs(A1fake-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
diff --git a/tests/trend-component-and-var-models/vm1.mod b/tests/trend-component-and-var-models/vm1.mod
new file mode 100644
index 0000000000000000000000000000000000000000..09ee2bd9a611ac014c18d4783908af6fb23d1212
--- /dev/null
+++ b/tests/trend-component-and-var-models/vm1.mod
@@ -0,0 +1,119 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112 A113 A114
+           A121 A122 A123 A124
+           A131 A132 A133 A134
+           A141 A142 A143 A144
+           A211 A212 A213 A214
+           A221 A222 A223 A224
+           A231 A232 A233 A234
+           A241 A242 A243 A244
+           A311 A312 A313 A314
+           A321 A322 A323 A324
+           A331 A332 A333 A334
+           A341 A342 A343 A344 ;
+
+A1 = randn(4);
+A2 = randn(4);
+A3 = randn(4);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A113 = A1(1,3);
+A114 = A1(1,4);
+A121 = A1(2,1);
+A122 = A1(2,2);
+A123 = A1(2,3);
+A124 = A1(2,4);
+A131 = A1(3,1);
+A132 = A1(3,2);
+A133 = A1(3,3);
+A134 = A1(3,4);
+A141 = A1(4,1);
+A142 = A1(4,2);
+A143 = A1(4,3);
+A144 = A1(4,4);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A213 = A2(1,3);
+A214 = A2(1,4);
+A221 = A2(2,1);
+A222 = A2(2,2);
+A223 = A2(2,3);
+A224 = A2(2,4);
+A231 = A2(3,1);
+A232 = A2(3,2);
+A233 = A2(3,3);
+A234 = A2(3,4);
+A241 = A2(4,1);
+A242 = A2(4,2);
+A243 = A2(4,3);
+A244 = A2(4,4);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A313 = A3(1,3);
+A314 = A3(1,4);
+A321 = A3(2,1);
+A322 = A3(2,2);
+A323 = A3(2,3);
+A324 = A3(2,4);
+A331 = A3(3,1);
+A332 = A3(3,2);
+A333 = A3(3,3);
+A334 = A3(3,4);
+A341 = A3(4,1);
+A342 = A3(4,2);
+A343 = A3(4,3);
+A344 = A3(4,4);
+
+var_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+y1 = A111*y1(-1) + A112*y2(-1) + A113*y3(-1) + A114*y4(-1) +
+     A211*y1(-2) + A212*y2(-2) + A213*y3(-2) + A214*y4(-2) +
+     A311*y1(-3) + A312*y2(-3) + A313*y3(-3) + A314*y4(-3) + e1; 
+
+[name='eq:y2']
+y2 = A121*y1(-1) + A122*y2(-1) + A123*y3(-1) + A124*y4(-1) +
+     A221*y1(-2) + A222*y2(-2) + A223*y3(-2) + A224*y4(-2) +
+     A321*y1(-3) + A322*y2(-3) + A323*y3(-3) + A324*y4(-3) + e2; 
+
+[name='eq:y3']
+y3 = A131*y1(-1) + A132*y2(-1) + A133*y3(-1) + A134*y4(-1) +
+     A231*y1(-2) + A232*y2(-2) + A233*y3(-2) + A234*y4(-2) +
+     A331*y1(-3) + A332*y2(-3) + A333*y3(-3) + A334*y4(-3) + e3; 
+
+[name='eq:y4']
+y4 = A141*y1(-1) + A142*y2(-1) + A143*y3(-1) + A144*y4(-1) +
+     A241*y1(-2) + A242*y2(-2) + A243*y3(-2) + A244*y4(-2) +
+     A341*y1(-3) + A342*y2(-3) + A343*y3(-3) + A344*y4(-3) + e4;
+
+end;
+
+[A0, A0star, AR, B] = get_companion_matrix('toto');
+
+if max(max(abs(AR(:,:,1)-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
+
+CompanionMatrix = [A1, A2, A3;
+                   eye(4), zeros(4, 8);
+                   zeros(4), eye(4), zeros(4)];
+
+if max(max(abs(CompanionMatrix-oo_.var.toto.CompanionMatrix)))>1e-12
+   error('Companion matrix is wrong.')
+end
diff --git a/tests/trend-component-and-var-models/vm2.mod b/tests/trend-component-and-var-models/vm2.mod
new file mode 100644
index 0000000000000000000000000000000000000000..638aac378e87136783e953664ca7ee4df6cee5d4
--- /dev/null
+++ b/tests/trend-component-and-var-models/vm2.mod
@@ -0,0 +1,119 @@
+var y4 y3 y2 y1;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112 A113 A114
+           A121 A122 A123 A124
+           A131 A132 A133 A134
+           A141 A142 A143 A144
+           A211 A212 A213 A214
+           A221 A222 A223 A224
+           A231 A232 A233 A234
+           A241 A242 A243 A244
+           A311 A312 A313 A314
+           A321 A322 A323 A324
+           A331 A332 A333 A334
+           A341 A342 A343 A344 ;
+
+A1 = randn(4);
+A2 = randn(4);
+A3 = randn(4);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A113 = A1(1,3);
+A114 = A1(1,4);
+A121 = A1(2,1);
+A122 = A1(2,2);
+A123 = A1(2,3);
+A124 = A1(2,4);
+A131 = A1(3,1);
+A132 = A1(3,2);
+A133 = A1(3,3);
+A134 = A1(3,4);
+A141 = A1(4,1);
+A142 = A1(4,2);
+A143 = A1(4,3);
+A144 = A1(4,4);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A213 = A2(1,3);
+A214 = A2(1,4);
+A221 = A2(2,1);
+A222 = A2(2,2);
+A223 = A2(2,3);
+A224 = A2(2,4);
+A231 = A2(3,1);
+A232 = A2(3,2);
+A233 = A2(3,3);
+A234 = A2(3,4);
+A241 = A2(4,1);
+A242 = A2(4,2);
+A243 = A2(4,3);
+A244 = A2(4,4);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A313 = A3(1,3);
+A314 = A3(1,4);
+A321 = A3(2,1);
+A322 = A3(2,2);
+A323 = A3(2,3);
+A324 = A3(2,4);
+A331 = A3(3,1);
+A332 = A3(3,2);
+A333 = A3(3,3);
+A334 = A3(3,4);
+A341 = A3(4,1);
+A342 = A3(4,2);
+A343 = A3(4,3);
+A344 = A3(4,4);
+
+var_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+y1 = A111*y1(-1) + A112*y2(-1) + A113*y3(-1) + A114*y4(-1) +
+     A211*y1(-2) + A212*y2(-2) + A213*y3(-2) + A214*y4(-2) +
+     A311*y1(-3) + A312*y2(-3) + A313*y3(-3) + A314*y4(-3) + e1; 
+
+[name='eq:y2']
+y2 = A121*y1(-1) + A122*y2(-1) + A123*y3(-1) + A124*y4(-1) +
+     A221*y1(-2) + A222*y2(-2) + A223*y3(-2) + A224*y4(-2) +
+     A321*y1(-3) + A322*y2(-3) + A323*y3(-3) + A324*y4(-3) + e2; 
+
+[name='eq:y3']
+y3 = A131*y1(-1) + A132*y2(-1) + A133*y3(-1) + A134*y4(-1) +
+     A231*y1(-2) + A232*y2(-2) + A233*y3(-2) + A234*y4(-2) +
+     A331*y1(-3) + A332*y2(-3) + A333*y3(-3) + A334*y4(-3) + e3; 
+
+[name='eq:y4']
+y4 = A141*y1(-1) + A142*y2(-1) + A143*y3(-1) + A144*y4(-1) +
+     A241*y1(-2) + A242*y2(-2) + A243*y3(-2) + A244*y4(-2) +
+     A341*y1(-3) + A342*y2(-3) + A343*y3(-3) + A344*y4(-3) + e4;
+
+end;
+
+[A0, A0star, AR, B] = get_companion_matrix('toto');
+
+if max(max(abs(AR(:,:,1)-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
+
+CompanionMatrix = [A1, A2, A3;
+                   eye(4), zeros(4, 8);
+                   zeros(4), eye(4), zeros(4)];
+
+if max(max(abs(CompanionMatrix-oo_.var.toto.CompanionMatrix)))>1e-12
+   error('Companion matrix is wrong.')
+end
diff --git a/tests/trend-component-and-var-models/vm3.mod b/tests/trend-component-and-var-models/vm3.mod
new file mode 100644
index 0000000000000000000000000000000000000000..496f956afb6cf3b2120d569091d058388d0dfc5c
--- /dev/null
+++ b/tests/trend-component-and-var-models/vm3.mod
@@ -0,0 +1,119 @@
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112 A113 A114
+           A121 A122 A123 A124
+           A131 A132 A133 A134
+           A141 A142 A143 A144
+           A211 A212 A213 A214
+           A221 A222 A223 A224
+           A231 A232 A233 A234
+           A241 A242 A243 A244
+           A311 A312 A313 A314
+           A321 A322 A323 A324
+           A331 A332 A333 A334
+           A341 A342 A343 A344 ;
+
+A1 = randn(4);
+A2 = randn(4);
+A3 = randn(4);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A113 = A1(1,3);
+A114 = A1(1,4);
+A121 = A1(2,1);
+A122 = A1(2,2);
+A123 = A1(2,3);
+A124 = A1(2,4);
+A131 = A1(3,1);
+A132 = A1(3,2);
+A133 = A1(3,3);
+A134 = A1(3,4);
+A141 = A1(4,1);
+A142 = A1(4,2);
+A143 = A1(4,3);
+A144 = A1(4,4);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A213 = A2(1,3);
+A214 = A2(1,4);
+A221 = A2(2,1);
+A222 = A2(2,2);
+A223 = A2(2,3);
+A224 = A2(2,4);
+A231 = A2(3,1);
+A232 = A2(3,2);
+A233 = A2(3,3);
+A234 = A2(3,4);
+A241 = A2(4,1);
+A242 = A2(4,2);
+A243 = A2(4,3);
+A244 = A2(4,4);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A313 = A3(1,3);
+A314 = A3(1,4);
+A321 = A3(2,1);
+A322 = A3(2,2);
+A323 = A3(2,3);
+A324 = A3(2,4);
+A331 = A3(3,1);
+A332 = A3(3,2);
+A333 = A3(3,3);
+A334 = A3(3,4);
+A341 = A3(4,1);
+A342 = A3(4,2);
+A343 = A3(4,3);
+A344 = A3(4,4);
+
+var_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y4']
+y4 = A141*y1(-1) + A142*y2(-1) + A143*y3(-1) + A144*y4(-1) +
+     A241*y1(-2) + A242*y2(-2) + A243*y3(-2) + A244*y4(-2) +
+     A341*y1(-3) + A342*y2(-3) + A343*y3(-3) + A344*y4(-3) + e4;
+
+[name='eq:y3']
+y3 = A131*y1(-1) + A132*y2(-1) + A133*y3(-1) + A134*y4(-1) +
+     A231*y1(-2) + A232*y2(-2) + A233*y3(-2) + A234*y4(-2) +
+     A331*y1(-3) + A332*y2(-3) + A333*y3(-3) + A334*y4(-3) + e3; 
+
+[name='eq:y2']
+y2 = A121*y1(-1) + A122*y2(-1) + A123*y3(-1) + A124*y4(-1) +
+     A221*y1(-2) + A222*y2(-2) + A223*y3(-2) + A224*y4(-2) +
+     A321*y1(-3) + A322*y2(-3) + A323*y3(-3) + A324*y4(-3) + e2; 
+
+[name='eq:y1']
+y1 = A111*y1(-1) + A112*y2(-1) + A113*y3(-1) + A114*y4(-1) +
+     A211*y1(-2) + A212*y2(-2) + A213*y3(-2) + A214*y4(-2) +
+     A311*y1(-3) + A312*y2(-3) + A313*y3(-3) + A314*y4(-3) + e1; 
+
+end;
+
+[A0, A0star, AR, B] = get_companion_matrix('toto');
+
+if max(max(abs(AR(:,:,1)-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
+
+CompanionMatrix = [A1, A2, A3;
+                   eye(4), zeros(4, 8);
+                   zeros(4), eye(4), zeros(4)];
+
+if max(max(abs(CompanionMatrix-oo_.var.toto.CompanionMatrix)))>1e-12
+   error('Companion matrix is wrong.')
+end
diff --git a/tests/trend-component-and-var-models/vm4.mod b/tests/trend-component-and-var-models/vm4.mod
new file mode 100644
index 0000000000000000000000000000000000000000..17c4ac3e64781a912bb71b1560ad14aab1c5c1aa
--- /dev/null
+++ b/tests/trend-component-and-var-models/vm4.mod
@@ -0,0 +1,52 @@
+// --+ options: json=compute, stochastic +--
+
+var y x z;
+
+varexo ex ey ez;
+
+parameters a_y_1 a_y_2 b_y_1 b_y_2 b_x_1 b_x_2 ; // VAR parameters
+
+parameters beta e_c_m c_z_1 c_z_2;               // PAC equation parameters
+
+a_y_1 =  .2;
+a_y_2 =  .3;
+b_y_1 =  .1;
+b_y_2 =  .4;
+b_x_1 = -.1;
+b_x_2 = -.2;
+
+beta  =  .9;
+e_c_m =  .1;
+c_z_1 =  .7;
+c_z_2 = -.3;
+
+var_model(model_name=toto, eqtags=['eq:x', 'eq:y']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = a_y_1*y(-1) + a_y_2*diff(x(-1)) + b_y_1*y(-2) + b_y_2*diff(x(-2)) + ey ;
+
+[name='eq:x', data_type='nonstationary']
+diff(x) = b_x_1*y(-2) + b_x_2*diff(x(-1)) + ex ;
+
+[name='eq:pac']
+diff(z) = e_c_m*(x(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman) + ez;
+
+end;
+
+shocks;
+    var ex = 1.0;
+    var ey = 1.0;
+    var ez = 1.0;
+end;
+
+[~, b0, ~] = get_companion_matrix_legacy('toto');
+
+[~, ~, b1, ~] = get_companion_matrix('toto');
+
+if any(abs(b0(:)-b1(:))>1e-9)
+   error('get_companion_matrix and get_comapnion_matrix_legacy do not return the same AR matrices.')
+end
\ No newline at end of file
diff --git a/tests/trend-component-and-var-models/vm5.mod b/tests/trend-component-and-var-models/vm5.mod
new file mode 100644
index 0000000000000000000000000000000000000000..f5bd780ed6add918baf21efc09c7f601ab534a58
--- /dev/null
+++ b/tests/trend-component-and-var-models/vm5.mod
@@ -0,0 +1,121 @@
+// --+ options: transform_unary_ops +--
+
+var y1 y2 y3 y4;
+
+varexo e1 e2 e3 e4;
+
+parameters A111 A112 A113 A114
+           A121 A122 A123 A124
+           A131 A132 A133 A134
+           A141 A142 A143 A144
+           A211 A212 A213 A214
+           A221 A222 A223 A224
+           A231 A232 A233 A234
+           A241 A242 A243 A244
+           A311 A312 A313 A314
+           A321 A322 A323 A324
+           A331 A332 A333 A334
+           A341 A342 A343 A344 ;
+
+A1 = randn(4);
+A2 = randn(4);
+A3 = randn(4);
+
+A111 = A1(1,1);
+A112 = A1(1,2);
+A113 = A1(1,3);
+A114 = A1(1,4);
+A121 = A1(2,1);
+A122 = A1(2,2);
+A123 = A1(2,3);
+A124 = A1(2,4);
+A131 = A1(3,1);
+A132 = A1(3,2);
+A133 = A1(3,3);
+A134 = A1(3,4);
+A141 = A1(4,1);
+A142 = A1(4,2);
+A143 = A1(4,3);
+A144 = A1(4,4);
+
+A211 = A2(1,1);
+A212 = A2(1,2);
+A213 = A2(1,3);
+A214 = A2(1,4);
+A221 = A2(2,1);
+A222 = A2(2,2);
+A223 = A2(2,3);
+A224 = A2(2,4);
+A231 = A2(3,1);
+A232 = A2(3,2);
+A233 = A2(3,3);
+A234 = A2(3,4);
+A241 = A2(4,1);
+A242 = A2(4,2);
+A243 = A2(4,3);
+A244 = A2(4,4);
+
+A311 = A3(1,1);
+A312 = A3(1,2);
+A313 = A3(1,3);
+A314 = A3(1,4);
+A321 = A3(2,1);
+A322 = A3(2,2);
+A323 = A3(2,3);
+A324 = A3(2,4);
+A331 = A3(3,1);
+A332 = A3(3,2);
+A333 = A3(3,3);
+A334 = A3(3,4);
+A341 = A3(4,1);
+A342 = A3(4,2);
+A343 = A3(4,3);
+A344 = A3(4,4);
+
+var_model(model_name=toto, eqtags=['eq:y1', 'eq:y2', 'eq:y3', 'eq:y4']);
+
+model;
+
+[name='eq:y1']
+log(y1) = A111*log(y1(-1)) + A112*y2(-1) + A113*y3(-1) + A114*y4(-1) +
+     A211*log(y1(-2)) + A212*y2(-2) + A213*y3(-2) + A214*y4(-2) +
+     A311*log(y1(-3)) + A312*y2(-3) + A313*y3(-3) + A314*y4(-3) + e1; 
+
+[name='eq:y2']
+y2 = A121*log(y1(-1)) + A122*y2(-1) + A123*y3(-1) + A124*y4(-1) +
+     A221*log(y1(-2)) + A222*y2(-2) + A223*y3(-2) + A224*y4(-2) +
+     A321*log(y1(-3)) + A322*y2(-3) + A323*y3(-3) + A324*y4(-3) + e2; 
+
+[name='eq:y3']
+y3 = A131*log(y1(-1)) + A132*y2(-1) + A133*y3(-1) + A134*y4(-1) +
+     A231*log(y1(-2)) + A232*y2(-2) + A233*y3(-2) + A234*y4(-2) +
+     A331*log(y1(-3)) + A332*y2(-3) + A333*y3(-3) + A334*y4(-3) + e3; 
+
+[name='eq:y4']
+y4 = A141*log(y1(-1)) + A142*y2(-1) + A143*y3(-1) + A144*y4(-1) +
+     A241*log(y1(-2)) + A242*y2(-2) + A243*y3(-2) + A244*y4(-2) +
+     A341*log(y1(-3)) + A342*y2(-3) + A343*y3(-3) + A344*y4(-3) + e4;
+
+end;
+
+[A0, A0star, AR, B] = get_companion_matrix('toto');
+
+if max(max(abs(AR(:,:,1)-A1)))>1e-12
+   error('First order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,2)-A2)))>1e-12
+   error('Second order autoregressive matrix is wrong.')
+end
+
+if max(max(abs(AR(:,:,3)-A3)))>1e-12
+   error('Third order autoregressive matrix is wrong.')
+end
+
+CompanionMatrix = [A1, A2, A3;
+                   eye(4), zeros(4, 8);
+                   zeros(4), eye(4), zeros(4)];
+
+if max(max(abs(CompanionMatrix-oo_.var.toto.CompanionMatrix)))>1e-12
+   error('Companion matrix is wrong.')
+end
diff --git a/tests/var-expectations/1/example.mod b/tests/var-expectations/1/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..0a607e56addcd9c78fd43a05a33b23e76f1a42ba
--- /dev/null
+++ b/tests/var-expectations/1/example.mod
@@ -0,0 +1,71 @@
+// --+ options: stochastic,json=compute +--
+
+var foo z x y;
+varexo e_x e_y e_z;
+parameters a b c d e f beta ;
+
+a =  .9;
+b = -.2;
+c =  .3;
+f =  .8;
+d =  .5;
+e =  .4;
+
+beta = 1/(1+.02);
+
+// Define a VAR model from a subset of equations in the model block.
+var_model(model_name = toto, eqtags = [ 'X' 'Y' 'Z' ]);
+
+/* Define a VAR_EXPECTATION_MODEL
+** ------------------------------
+**
+** model_name:       the name of the VAR_EXPECTATION_MODEL (mandatory).
+** var_model_name:   the name of the VAR model used for the expectations (mandatory).
+** variable:         the name of the variable to be forecasted (mandatory).
+** horizon:          the horizon forecast (mandatory).
+** discount:         the discount factor, which can be a value or a declared parameter (default is 1.0, no discounting).
+**
+**
+** The `horizon` parameter can be an integer in which case the (discounted) `horizon` step ahead forecast
+** is computed using the VAR model `var_model_name`. Alternatively, `horizon` can be a range. In this case
+** VAR_EXPECTATION_MODEL returns a discounted sum of expected values. If `horizon` is set equal to the range
+** 0:Inf, then VAR_EXPECTATION_MODEL computes:
+**
+**                                       ∑ βʰ Eₜ[yₜ₊ₕ]
+**
+** where the sum is over h=0,…,∞ and the conditional expectations are computed with VAR model `var_model_name`.
+*/
+
+var_expectation_model(model_name = varexp, expression = x, auxiliary_model_name = toto, horizon = 1, discount = beta)  ;
+
+
+model;
+[ name = 'X' ]
+x = a*x(-1) + b*x(-2) + c*z(-2) + e_x;
+[ name = 'Z' ]
+z = f*z(-1) + e_z;
+[ name = 'Y' ]
+y = d*y(-2) + e*z(-1) + e_y;
+
+foo = .5*foo(-1) + var_expectation(varexp);
+end;
+
+
+// Initialize the VAR expectation model, will build the companion matrix of the VAR.
+var_expectation.initialize('varexp')
+
+// Update VAR_EXPECTATION reduced form parameters
+var_expectation.update('varexp');
+
+/*
+** REMARK The VAR model is such that x depends on past values of x
+** (xₜ₋₁ and xₜ₋₂) and on zₜ₋₂ ⇒ yₜ₋₁, yₜ₋₂ and zₜ₋₁ do not bring any
+** useful information for predicting xₜ₊₁. Consequently the reduced
+** form parameters associated to yₜ₋₁, yₜ₋₂ and zₜ₋₁ have to be zero.
+*/
+
+weights = M_.params(M_.var_expectation.varexp.param_indices);
+
+if weights(2) || weights(3) || weights(5) || ~weights(1) || ~weights(4) || ~weights(6)
+   error('Wrong reduced form parameter for VAR_EXPECTATION_MODEL')
+end
\ No newline at end of file
diff --git a/tests/var-expectations/10/example.mod b/tests/var-expectations/10/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..7b1542ee9e4e685d452e698e35aaa4425f2a540f
--- /dev/null
+++ b/tests/var-expectations/10/example.mod
@@ -0,0 +1,69 @@
+// --+ options: stochastic,json=compute +--
+
+var foo z x y;
+varexo e_x e_y e_z;
+parameters a b c d e f beta ;
+
+a =  .9;
+b = -.2;
+c =  .3;
+f =  .8;
+d =  .5;
+e =  .4;
+
+beta = 1/(1+.02);
+
+// Define a VAR model from a subset of equations in the model block.
+var_model(model_name = toto, eqtags = [ 'X' 'Y' 'Z' ]);
+
+// Define a VAR_EXPECTATION_MODEL
+var_expectation_model(model_name = varexp, expression = diff(log(x)), auxiliary_model_name = toto, horizon = 1, discount = beta)  ;
+
+model;
+[ name = 'X' ]
+diff(log(x)) = a*diff(log(x(-1))) + b*diff(log(x(-2))) + c*diff(z(-2)) + e_x;
+[ name = 'Z' ]
+diff(z) = f*diff(z(-1)) + e_z;
+[ name = 'Y' ]
+log(y) = d*log(y(-2)) + e*diff(z(-1)) + e_y;
+
+foo = var_expectation(varexp);
+end;
+
+// Initialize the VAR expectation model, will build the companion matrix of the VAR.
+var_expectation.initialize('varexp')
+
+// Update VAR_EXPECTATION reduced form parameters
+var_expectation.update('varexp');
+
+// Print expanded VAR_EXPECTATION expression in a file (to be included in substitution.mod).
+var_expectation.print('varexp');
+
+shocks;
+  var e_x = .01;
+  var e_y = .01;
+  var e_z = .01;
+end;
+
+verbatim;
+  initialconditions =zeros(3,4);
+  initialconditions(3,1) = .1; % foo(-1)
+  initialconditions(:,2) = .2; % y(-1)
+  initialconditions(3,3) = .3; % z(-1)
+  initialconditions(2,3) = .4; % z(-2)
+  initialconditions(3,4) = .5; % x(-1)
+  initialconditions(2,4) = .6; % x(-2)
+  initialconditions(1,4) = .7; % x(-3)
+  initialconditions = ...
+  dseries(initialconditions, dates('2000Q1'), {'foo', 'y','z', 'x'});
+  set_dynare_seed('default');
+  ts = simul_backward_model(initialconditions, 15);
+  foo = ts.foo.data;
+  % Evaluate the (VAR) expectation term
+  ts{'toto'} = example.var_expectations.varexp.evaluate(ts);
+  % Check tthat the evaluation is correct.
+  range = dates('2000Q4'):dates('2004Q2');
+  if max(abs(ts(range).foo.data-ts(range).toto.data))>1e-5
+     error('Expectation term evaluations do not match!')
+  end
+end;
\ No newline at end of file
diff --git a/tests/var-expectations/2/example.mod b/tests/var-expectations/2/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..59d59f906067fc87843dd69b4adf243c291a47c0
--- /dev/null
+++ b/tests/var-expectations/2/example.mod
@@ -0,0 +1,80 @@
+// --+ options: stochastic,json=compute +--
+
+var foo z x y;
+varexo e_x e_y e_z;
+parameters a b c d e f beta ;
+
+a =  .9;
+b = -.2;
+c =  .3;
+f =  .8;
+d =  .5;
+e =  .4;
+
+beta = 1/(1+.02);
+
+// Define a VAR model from a subset of equations in the model block.
+var_model(model_name = toto, eqtags = [ 'X' 'Y' 'Z' ]);
+
+/* Define a VAR_EXPECTATION_MODEL
+** ------------------------------
+**
+** model_name:       the name of the VAR_EXPECTATION_MODEL (mandatory).
+** var_model_name:   the name of the VAR model used for the expectations (mandatory).
+** variable:         the name of the variable to be forecasted (mandatory).
+** horizon:          the horizon forecast (mandatory).
+** discount:         the discount factor, which can be a value or a declared parameter (default is 1.0, no discounting).
+**
+**
+** The `horizon` parameter can be an integer in which case the (discounted) `horizon` step ahead forecast
+** is computed using the VAR model `var_model_name`. Alternatively, `horizon` can be a range. In this case
+** VAR_EXPECTATION_MODEL returns a discounted sum of expected values. If `horizon` is set equal to the range
+** 0:Inf, then VAR_EXPECTATION_MODEL computes:
+**
+**                                       ∑ βʰ Eₜ[yₜ₊ₕ]
+**
+** where the sum is over h=0,…,∞ and the conditional expectations are computed with VAR model `var_model_name`.
+*/
+
+var_expectation_model(model_name = varexp, expression = x, auxiliary_model_name = toto, horizon = 2, discount = beta)  ;
+
+
+model;
+[ name = 'X' ]
+x = a*x(-1) + b*x(-2) + c*z(-2) + e_x;
+[ name = 'Z' ]
+z = f*z(-1) + e_z;
+[ name = 'Y' ]
+y = d*y(-2) + e*z(-1) + e_y;
+
+foo = .5*foo(-1) + var_expectation(varexp);
+end;
+
+
+// Initialize the VAR expectation model, will build the companion matrix of the VAR.
+var_expectation.initialize('varexp')
+
+// Update VAR_EXPECTATION reduced form parameters
+var_expectation.update('varexp');
+
+// Print equations where the variable appears in
+fprintf('x is in: \n')
+print_equations('x')
+fprintf('\n')
+
+fprintf('y is in: \n')
+print_equations('y', true)
+fprintf('\n')
+
+/*
+** REMARK The VAR model is such that x depends on past values of x
+** (xₜ₋₁ and xₜ₋₂) and on zₜ₋₂ ⇒ yₜ₋₁, yₜ₋₂ and zₜ₋₁ do not bring any
+** useful information for predicting xₜ₊₁. Consequently the reduced
+** form parameters associated to yₜ₋₁, yₜ₋₂ and zₜ₋₁ have to be zero.
+*/
+
+weights = M_.params(M_.var_expectation.varexp.param_indices);
+
+if weights(2) || ~weights(3) || weights(5) || ~weights(1) || ~weights(4) || ~weights(6)
+   error('Wrong reduced form parameter for VAR_EXPECTATION_MODEL')
+end
\ No newline at end of file
diff --git a/tests/var-expectations/3/example.mod b/tests/var-expectations/3/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..6298ab64bb138190b8d36e346c4f6f07aeda39df
--- /dev/null
+++ b/tests/var-expectations/3/example.mod
@@ -0,0 +1,71 @@
+// --+ options: stochastic,json=compute +--
+
+var foo z x y;
+varexo e_x e_y e_z;
+parameters a b c d e f beta ;
+
+a =  .9;
+b = -.2;
+c =  .3;
+f =  .8;
+d =  .5;
+e =  .4;
+
+beta = 1/(1+.02);
+
+// Define a VAR model from a subset of equations in the model block.
+var_model(model_name = toto, eqtags = [ 'X' 'Y' 'Z' ]);
+
+/* Define a VAR_EXPECTATION_MODEL
+** ------------------------------
+**
+** model_name:       the name of the VAR_EXPECTATION_MODEL (mandatory).
+** var_model_name:   the name of the VAR model used for the expectations (mandatory).
+** variable:         the name of the variable to be forecasted (mandatory).
+** horizon:          the horizon forecast (mandatory).
+** discount:         the discount factor, which can be a value or a declared parameter (default is 1.0, no discounting).
+**
+**
+** The `horizon` parameter can be an integer in which case the (discounted) `horizon` step ahead forecast
+** is computed using the VAR model `var_model_name`. Alternatively, `horizon` can be a range. In this case
+** VAR_EXPECTATION_MODEL returns a discounted sum of expected values. If `horizon` is set equal to the range
+** 0:Inf, then VAR_EXPECTATION_MODEL computes:
+**
+**                                       ∑ βʰ Eₜ[yₜ₊ₕ]
+**
+** where the sum is over h=0,…,∞ and the conditional expectations are computed with VAR model `var_model_name`.
+*/
+
+var_expectation_model(model_name = varexp, expression = x, auxiliary_model_name = toto, horizon = 0:Inf, discount = beta)  ;
+
+
+model;
+[ name = 'X' ]
+x = a*x(-1) + b*x(-2) + c*z(-2) + e_x;
+[ name = 'Z' ]
+z = f*z(-1) + e_z;
+[ name = 'Y' ]
+y = d*y(-2) + e*z(-1) + e_y;
+
+foo = .5*foo(-1) + var_expectation(varexp);
+end;
+
+// Initialize the VAR expectation model, will build the companion matrix of the VAR.
+var_expectation.initialize('varexp')
+
+// Update VAR_EXPECTATION reduced form parameters
+var_expectation.update('varexp');
+
+/*
+** REMARK The VAR model is such that x depends on past values of x
+** (xₜ₋₁ and xₜ₋₂) and on zₜ₋₂. Consequently the reduced
+** form parameters associated to yₜ₋₁, yₜ₋₂ have to be zero.
+*/
+
+weights = M_.params(M_.var_expectation.varexp.param_indices);
+
+if weights(2) || ~weights(3) || weights(5) || ~weights(1) || ~weights(4) || ~weights(6)
+   error('Wrong reduced form parameter for VAR_EXPECTATION_MODEL')
+end
+
+save('weights.mat','weights');
\ No newline at end of file
diff --git a/tests/var-expectations/4/example.mod b/tests/var-expectations/4/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..2ec4fe30a618a6f76eb4a5e2d83db23b1c75776b
--- /dev/null
+++ b/tests/var-expectations/4/example.mod
@@ -0,0 +1,77 @@
+// --+ options: stochastic,json=compute +--
+
+var foo z x y;
+varexo e_x e_y e_z;
+parameters a b c d e f beta ;
+
+a =  .9;
+b = -.2;
+c =  .3;
+f =  .8;
+d =  .5;
+e =  .4;
+
+beta = 1/(1+.02);
+
+// Define a VAR model from a subset of equations in the model block.
+var_model(model_name = toto, eqtags = [ 'X' 'Y' 'Z' ]);
+
+/* Define a VAR_EXPECTATION_MODEL
+** ------------------------------
+**
+** model_name:       the name of the VAR_EXPECTATION_MODEL (mandatory).
+** var_model_name:   the name of the VAR model used for the expectations (mandatory).
+** variable:         the name of the variable to be forecasted (mandatory).
+** horizon:          the horizon forecast (mandatory).
+** discount:         the discount factor, which can be a value or a declared parameter (default is 1.0, no discounting).
+**
+**
+** The `horizon` parameter can be an integer in which case the (discounted) `horizon` step ahead forecast
+** is computed using the VAR model `var_model_name`. Alternatively, `horizon` can be a range. In this case
+** VAR_EXPECTATION_MODEL returns a discounted sum of expected values. If `horizon` is set equal to the range
+** 0:Inf, then VAR_EXPECTATION_MODEL computes:
+**
+**                                       ∑ βʰ Eₜ[yₜ₊ₕ]
+**
+** where the sum is over h=0,…,∞ and the conditional expectations are computed with VAR model `var_model_name`.
+*/
+
+var_expectation_model(model_name = varexp, expression = x, auxiliary_model_name = toto, horizon = 0:500, discount = beta)  ;
+
+
+model;
+[ name = 'X' ]
+x = a*x(-1) + b*x(-2) + c*z(-2) + e_x;
+[ name = 'Z' ]
+z = f*z(-1) + e_z;
+[ name = 'Y' ]
+y = d*y(-2) + e*z(-1) + e_y;
+
+foo = .5*foo(-1) + var_expectation(varexp);
+end;
+
+// Initialize the VAR expectation model, will build the companion matrix of the VAR.
+var_expectation.initialize('varexp')
+
+// Update VAR_EXPECTATION reduced form parameters
+var_expectation.update('varexp');
+
+/*
+** REMARK The VAR model is such that x depends on past values of x
+** (xₜ₋₁ and xₜ₋₂) and on zₜ₋₂. Consequently the reduced
+** form parameters associated to yₜ₋₁, yₜ₋₂ have to be zero.
+*/
+
+weights = M_.params(M_.var_expectation.varexp.param_indices);
+
+if weights(2) || ~weights(3) || weights(5) || ~weights(1) || ~weights(4) || ~weights(6)
+   error('Wrong reduced form parameter for VAR_EXPECTATION_MODEL')
+end
+
+WEIGHTS = load('../3/weights.mat');
+
+if max(abs(weights-WEIGHTS.weights))>1e-12
+   error('Inconsistent results in var-expectations/3 and var-expectations/4.')
+end
+
+delete('../3/weights.mat')
\ No newline at end of file
diff --git a/tests/var-expectations/5/example.mod b/tests/var-expectations/5/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..8f088186b282fe7686f22570e0fdefe007194655
--- /dev/null
+++ b/tests/var-expectations/5/example.mod
@@ -0,0 +1,68 @@
+// --+ options: stochastic,json=compute +--
+
+var foo z x y;
+varexo e_x e_y e_z;
+parameters a b c d e f beta ;
+
+a =  .9;
+b = -.2;
+c =  .3;
+f =  .8;
+d =  .5;
+e =  .4;
+
+beta = 1/(1+.02);
+
+// Define a VAR model from a subset of equations in the model block.
+var_model(model_name = toto, eqtags = [ 'X' 'Y' 'Z' ]);
+
+/* Define a VAR_EXPECTATION_MODEL
+** ------------------------------
+**
+** model_name:       the name of the VAR_EXPECTATION_MODEL (mandatory).
+** var_model_name:   the name of the VAR model used for the expectations (mandatory).
+** variable:         the name of the variable to be forecasted (mandatory).
+** horizon:          the horizon forecast (mandatory).
+** discount:         the discount factor, which can be a value or a declared parameter (default is 1.0, no discounting).
+**
+**
+** The `horizon` parameter can be an integer in which case the (discounted) `horizon` step ahead forecast
+** is computed using the VAR model `var_model_name`. Alternatively, `horizon` can be a range. In this case
+** VAR_EXPECTATION_MODEL returns a discounted sum of expected values. If `horizon` is set equal to the range
+** 0:Inf, then VAR_EXPECTATION_MODEL computes:
+**
+**                                       ∑ βʰ Eₜ[yₜ₊ₕ]
+**
+** where the sum is over h=0,…,∞ and the conditional expectations are computed with VAR model `var_model_name`.
+*/
+
+var_expectation_model(model_name = varexp, expression = x, auxiliary_model_name = toto, horizon = 15:50, discount = beta)  ;
+
+model;
+[ name = 'X' ]
+x = a*x(-1) + b*x(-2) + c*z(-2) + e_x;
+[ name = 'Z' ]
+z = f*z(-1) + e_z;
+[ name = 'Y' ]
+y = d*y(-2) + e*z(-1) + e_y;
+
+foo = .5*foo(-1) + var_expectation(varexp);
+end;
+
+// Initialize the VAR expectation model, will build the companion matrix of the VAR.
+var_expectation.initialize('varexp')
+
+// Update VAR_EXPECTATION reduced form parameters
+var_expectation.update('varexp');
+
+/*
+** REMARK The VAR model is such that x depends on past values of x
+** (xₜ₋₁ and xₜ₋₂) and on zₜ₋₂. Consequently the reduced
+** form parameters associated to yₜ₋₁, yₜ₋₂ have to be zero.
+*/
+
+weights = M_.params(M_.var_expectation.varexp.param_indices);
+
+if weights(2) || ~weights(3) || weights(5) || ~weights(1) || ~weights(4) || ~weights(6)
+   error('Wrong reduced form parameter for VAR_EXPECTATION_MODEL')
+end
\ No newline at end of file
diff --git a/tests/var-expectations/6/example.mod b/tests/var-expectations/6/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..65ba9eff672029197794f68b954502f61eb3023b
--- /dev/null
+++ b/tests/var-expectations/6/example.mod
@@ -0,0 +1,109 @@
+// --+ options: stochastic,transform_unary_ops,json=compute +--
+
+var foo x1 x2 x1bar x2bar;
+
+varexo ex1 ex2 ex1bar ex2bar;
+
+parameters a_x1_0 a_x1_0_ a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+       beta ;
+
+a_x1_0 =  -.9;
+a_x1_0_ =  -.8;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta = 1/(1+.02);
+
+// Define a TREND_COMPONENT model from a subset of equations in the model block.
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+/* Define a VAR_EXPECTATION_MODEL
+** ------------------------------
+**
+** model_name:             the name of the VAR_EXPECTATION_MODEL (mandatory).
+** auxiliary_model_name:   the name of the VAR model used for the expectations (mandatory).
+** variable:               the name of the variable to be forecasted (mandatory).
+** horizon:                the horizon forecast (mandatory).
+** discount:               the discount factor, which can be a value or a declared parameter (default is 1.0, no discounting).
+**
+**
+** The `horizon` parameter can be an integer in which case the (discounted) `horizon` step ahead forecast
+** is computed using the VAR model `var_model_name`. Alternatively, `horizon` can be a range. In this case
+** VAR_EXPECTATION_MODEL returns a discounted sum of expected values. If `horizon` is set equal to the range
+** 0:Inf, then VAR_EXPECTATION_MODEL computes:
+**
+**                                       ∑ βʰ Eₜ[yₜ₊ₕ]
+**
+** where the sum is over h=0,…,∞ and the conditional expectations are computed with VAR model `var_model_name`.
+*/
+
+var_expectation_model(model_name = varexp, expression = x1, auxiliary_model_name = toto, horizon = 15:50, discount = beta)  ;
+
+
+model;
+
+[name='eq:x1', data_type='nonstationary']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1))+a_x1_0_*(x2(-1)-x2bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2', data_type='nonstationary']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar', data_type='nonstationary']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar', data_type='nonstationary']
+x2bar = x2bar(-1) + ex2bar;
+
+foo = .5*foo(-1) + var_expectation(varexp);
+end;
+
+// Initialize the VAR expectation model, will build the companion matrix of the VAR.
+var_expectation.initialize('varexp')
+
+// Update VAR_EXPECTATION reduced form parameters
+var_expectation.update('varexp');
+
+weights = M_.params(M_.var_expectation.varexp.param_indices);
+
+if ~all(weights(1:6)) || ~all(weights(9:10)) || weights(7) || weights(8) || weights(11) || weights(12)
+   error('Wrong reduced form parameter for VAR_EXPECTATION_MODEL')
+end
+
+var_expectation.print('varexp');
+
+shocks;
+  var ex1 = .01;
+  var ex2 = .01;
+  var ex1bar = .02;
+  var ex2bar = .02;
+end;
+
+
+verbatim;
+  initialconditions =zeros(3,5);
+  initialconditions(3,1) = .10; % foo(-1)
+  initialconditions(3,2) = .20; % x1(-1)
+  initialconditions(2,2) = .22; % x1(-2)
+  initialconditions(1,2) = .24; % x1(-3)
+  initialconditions(3,3) = .30; % x2(-1)
+  initialconditions(2,3) = .32; % x2(-2)
+  initialconditions(1,3) = .34; % x2(-3)
+  initialconditions(3,4) = .25; % x1bar(-1)
+  initialconditions(3,5) = .25; % x2bar(-1)
+  initialconditions = ...
+  dseries(initialconditions, dates('2000Q1'), {'foo', 'x1','x2', 'x1bar', 'x2bar'});
+    set_dynare_seed('default');
+  ts = simul_backward_model(initialconditions, 100);
+  foo = ts.foo.data;
+  save('example.mat', 'foo');
+end;
\ No newline at end of file
diff --git a/tests/var-expectations/6/substitution.mod b/tests/var-expectations/6/substitution.mod
new file mode 100644
index 0000000000000000000000000000000000000000..6deae093febd06fa236eda9e37f6144942095710
--- /dev/null
+++ b/tests/var-expectations/6/substitution.mod
@@ -0,0 +1,76 @@
+// --+ options: stochastic,transform_unary_ops,json=compute +--
+
+var foo x1 x2 x1bar x2bar;
+
+varexo ex1 ex2 ex1bar ex2bar;
+
+parameters a_x1_0 a_x1_0_ a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+       beta ;
+
+a_x1_0 =  -.9;
+a_x1_0_ =  -.8;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+@#include "example/model/var-expectations/varexp-parameters.inc"
+
+beta = 1/(1+.02);
+
+model;
+
+[name='eq:x1', data_type='nonstationary']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1))+a_x1_0_*(x2(-1)-x2bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;
+
+[name='eq:x2', data_type='nonstationary']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;
+
+[name='eq:x1bar', data_type='nonstationary']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar', data_type='nonstationary']
+x2bar = x2bar(-1) + ex2bar;
+
+foo = .5*foo(-1) +
+@#include "example/model/var-expectations/varexp-expression.inc"
+;
+end;
+
+shocks;
+  var ex1 = .01;
+  var ex2 = .01;
+  var ex1bar = .02;
+  var ex2bar = .02;
+end;
+
+
+verbatim;
+  initialconditions =zeros(3,5);
+  initialconditions(3,1) = .10; % foo(-1)
+  initialconditions(3,2) = .20; % x1(-1)
+  initialconditions(2,2) = .22; % x1(-2)
+  initialconditions(1,2) = .24; % x1(-3)
+  initialconditions(3,3) = .30; % x2(-1)
+  initialconditions(2,3) = .32; % x2(-2)
+  initialconditions(1,3) = .34; % x2(-3)
+  initialconditions(3,4) = .25; % x1bar(-1)
+  initialconditions(3,5) = .25; % x2bar(-1)
+  initialconditions = ...
+  dseries(initialconditions, dates('2000Q1'), {'foo', 'x1','x2', 'x1bar', 'x2bar'});
+    set_dynare_seed('default');
+  ts = simul_backward_model(initialconditions, 100);
+  ex = load('example.mat');
+  delete('example.mat')
+  if max(abs(ex.foo-ts.foo.data))>1e-12
+     error('Simulations do not match!')
+  end
+end;
\ No newline at end of file
diff --git a/tests/var-expectations/7/example.mod b/tests/var-expectations/7/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..4aa7b4374c32a2475e2235a84c406624fe61c36b
--- /dev/null
+++ b/tests/var-expectations/7/example.mod
@@ -0,0 +1,65 @@
+// --+ options: stochastic,json=compute +--
+
+var foo z x y;
+varexo e_x e_y e_z;
+parameters a b c d e f beta ;
+
+a =  .9;
+b = -.2;
+c =  .3;
+f =  .8;
+d =  .5;
+e =  .4;
+
+beta = 1/(1+.02);
+
+// Define a VAR model from a subset of equations in the model block.
+var_model(model_name = toto, eqtags = [ 'X' 'Y' 'Z' ]);
+
+// Define a VAR_EXPECTATION_MODEL
+var_expectation_model(model_name = varexp, expression = diff(x), auxiliary_model_name = toto, horizon = 1, discount = beta)  ;
+
+
+model;
+[ name = 'X' ]
+diff(x) = a*diff(x(-1)) + b*diff(x(-2)) + c*z(-2) + e_x;
+[ name = 'Z' ]
+z = f*z(-1) + e_z;
+[ name = 'Y' ]
+log(y) = d*log(y(-2)) + e*z(-1) + e_y;
+
+foo = .5*foo(-1) + var_expectation(varexp);
+end;
+
+// Initialize the VAR expectation model, will build the companion matrix of the VAR.
+var_expectation.initialize('varexp')
+
+// Update VAR_EXPECTATION reduced form parameters
+var_expectation.update('varexp');
+
+// Print expanded VAR_EXPECTATION expression in a file (to be included in substitution.mod).
+var_expectation.print('varexp');
+
+shocks;
+  var e_x = .01;
+  var e_y = .01;
+  var e_z = .01;
+end;
+
+
+verbatim;
+  initialconditions =zeros(3,4);
+  initialconditions(3,1) = .1; % foo(-1)
+  initialconditions(:,2) = .2; % y(-1)
+  initialconditions(3,3) = .3; % z(-1)
+  initialconditions(2,3) = .4; % z(-2)
+  initialconditions(3,4) = .5; % x(-1)
+  initialconditions(2,4) = .6; % x(-2)
+  initialconditions(1,4) = .7; % x(-3)
+  initialconditions = ...
+  dseries(initialconditions, dates('2000Q1'), {'foo', 'y','z', 'x'});
+    set_dynare_seed('default');
+  ts = simul_backward_model(initialconditions, 100);
+  foo = ts.foo.data;
+  save('example.mat', 'foo');
+end;
diff --git a/tests/var-expectations/7/substitution.mod b/tests/var-expectations/7/substitution.mod
new file mode 100644
index 0000000000000000000000000000000000000000..2cfb853f9b046a7536409840dd6332e7fef4f1b2
--- /dev/null
+++ b/tests/var-expectations/7/substitution.mod
@@ -0,0 +1,61 @@
+// --+ options: stochastic,transform_unary_ops,json=compute +--
+
+var foo z x y;
+varexo e_x e_y e_z;
+parameters a b c d e f beta ;
+
+a =  .9;
+b = -.2;
+c =  .3;
+f =  .8;
+d =  .5;
+e =  .4;
+
+@#include "example/model/var-expectations/varexp-parameters.inc"
+
+beta = 1/(1+.02);
+
+// Define a VAR_EXPECTATION_MODEL
+var_model(model_name = toto, eqtags = [ 'X' 'Y' 'Z' ]);
+
+model;
+[ name = 'X' ]
+diff(x) = a*diff(x(-1)) + b*diff(x(-2)) + c*z(-2) + e_x;
+[ name = 'Z' ]
+z = f*z(-1) + e_z;
+[ name = 'Y' ]
+log(y) = d*log(y(-2)) + e*z(-1) + e_y;
+
+foo = .5*foo(-1) +
+@#include "example/model/var-expectations/varexp-expression.inc"
+;
+end;
+
+shocks;
+  var e_x = .01;
+  var e_y = .01;
+  var e_z = .01;
+end;
+
+verbatim;
+  initialconditions =zeros(3,4);
+  initialconditions(3,1) = .1; % foo(-1)
+  initialconditions(:,2) = .2; % y(-1)
+  initialconditions(3,3) = .3; % z(-1)
+  initialconditions(2,3) = .4; % z(-2)
+  initialconditions(3,4) = .5; % x(-1)
+  initialconditions(2,4) = .6; % x(-2)
+  initialconditions(1,4) = .7; % x(-3)
+  initialconditions = ...
+  dseries(initialconditions, dates('2000Q1'), {'foo', 'y','z', 'x'});
+    set_dynare_seed('default');
+  ts = simul_backward_model(initialconditions, 100);
+  ex = load('example.mat');
+end;
+
+delete('example.mat')
+
+if max(abs(ex.foo-ts.foo.data))>1e-12
+   error('Simulations do not match!')
+end
+
diff --git a/tests/var-expectations/8/example.mod b/tests/var-expectations/8/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..cc14a3e9e45d08adf272cacf0294a3a34beabe2a
--- /dev/null
+++ b/tests/var-expectations/8/example.mod
@@ -0,0 +1,63 @@
+// --+ options: stochastic,json=compute +--
+
+var foo z x y;
+varexo e_x e_y e_z;
+parameters a b c d e f beta ;
+
+a =  .9;
+b = -.2;
+c =  .3;
+f =  .8;
+d =  .5;
+e =  .4;
+
+beta = 1/(1+.02);
+
+// Define a VAR model from a subset of equations in the model block.
+var_model(model_name = toto, eqtags = [ 'X' 'Y' 'Z' ]);
+
+// Define a VAR_EXPECTATION_MODEL
+var_expectation_model(model_name = varexp, expression = diff(log(x)), auxiliary_model_name = toto, horizon = 1, discount = beta)  ;
+
+model;
+[ name = 'X' ]
+diff(log(x)) = a*diff(log(x(-1))) + b*diff(log(x(-2))) + c*diff(z(-2)) + e_x;
+[ name = 'Z' ]
+diff(z) = f*diff(z(-1)) + e_z;
+[ name = 'Y' ]
+log(y) = d*log(y(-2)) + e*diff(z(-1)) + e_y;
+
+foo = .5*foo(-1) + var_expectation(varexp);
+end;
+
+// Initialize the VAR expectation model, will build the companion matrix of the VAR.
+var_expectation.initialize('varexp')
+
+// Update VAR_EXPECTATION reduced form parameters
+var_expectation.update('varexp');
+
+// Print expanded VAR_EXPECTATION expression in a file (to be included in substitution.mod).
+var_expectation.print('varexp');
+
+shocks;
+  var e_x = .01;
+  var e_y = .01;
+  var e_z = .01;
+end;
+
+verbatim;
+  initialconditions =zeros(3,4);
+  initialconditions(3,1) = .1; % foo(-1)
+  initialconditions(:,2) = .2; % y(-1)
+  initialconditions(3,3) = .3; % z(-1)
+  initialconditions(2,3) = .4; % z(-2)
+  initialconditions(3,4) = .5; % x(-1)
+  initialconditions(2,4) = .6; % x(-2)
+  initialconditions(1,4) = .7; % x(-3)
+  initialconditions = ...
+  dseries(initialconditions, dates('2000Q1'), {'foo', 'y','z', 'x'});
+    set_dynare_seed('default');
+  ts = simul_backward_model(initialconditions, 100);
+  foo = ts.foo.data;
+  save('example.mat', 'foo');
+end;
\ No newline at end of file
diff --git a/tests/var-expectations/8/substitution.mod b/tests/var-expectations/8/substitution.mod
new file mode 100644
index 0000000000000000000000000000000000000000..96b9bbb61732163662782f3f8ea6e8067962d410
--- /dev/null
+++ b/tests/var-expectations/8/substitution.mod
@@ -0,0 +1,57 @@
+// --+ options: stochastic,transform_unary_ops,json=compute +--
+
+var foo z x y;
+varexo e_x e_y e_z;
+parameters a b c d e f beta ;
+
+a =  .9;
+b = -.2;
+c =  .3;
+f =  .8;
+d =  .5;
+e =  .4;
+
+@#include "example/model/var-expectations/varexp-parameters.inc"
+
+beta = 1/(1+.02);
+
+model;
+[ name = 'X' ]
+diff(log(x)) = a*diff(log(x(-1))) + b*diff(log(x(-2))) + c*diff(z(-2)) + e_x;
+[ name = 'Z' ]
+diff(z) = f*diff(z(-1)) + e_z;
+[ name = 'Y' ]
+log(y) = d*log(y(-2)) + e*diff(z(-1)) + e_y;
+
+foo = .5*foo(-1) +
+@#include "example/model/var-expectations/varexp-expression.inc"
+;
+end;
+
+shocks;
+  var e_x = .01;
+  var e_y = .01;
+  var e_z = .01;
+end;
+
+verbatim;
+  initialconditions =zeros(3,4);
+  initialconditions(3,1) = .1; % foo(-1)
+  initialconditions(:,2) = .2; % y(-1)
+  initialconditions(3,3) = .3; % z(-1)
+  initialconditions(2,3) = .4; % z(-2)
+  initialconditions(3,4) = .5; % x(-1)
+  initialconditions(2,4) = .6; % x(-2)
+  initialconditions(1,4) = .7; % x(-3)
+  initialconditions = ...
+  dseries(initialconditions, dates('2000Q1'), {'foo', 'y','z', 'x'});
+  set_dynare_seed('default');
+  ts = simul_backward_model(initialconditions, 100);
+  ex = load('example.mat');
+end;
+
+delete('example.mat')
+
+if max(abs(ex.foo-ts.foo.data))>1e-12
+   error('Simulations do not match!')
+end
\ No newline at end of file
diff --git a/tests/var-expectations/9/example.mod b/tests/var-expectations/9/example.mod
new file mode 100644
index 0000000000000000000000000000000000000000..b39bf4e9060ab117c09fa49ac32abcf4bc61083d
--- /dev/null
+++ b/tests/var-expectations/9/example.mod
@@ -0,0 +1,82 @@
+// --+ options: stochastic,transform_unary_ops,json=compute +--
+
+var foo x1 x2 x1bar x2bar;
+
+varexo ex1 ex2 ex1bar ex2bar;
+
+parameters a_x1_0 a_x1_0_ a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+       beta
+       alpha ;
+
+a_x1_0 =  -.9;
+a_x1_0_ =  -.8;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta = 1/(1+.02);
+alpha = .5;
+
+// Define a TREND_COMPONENT model from a subset of equations in the model block.
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+/* Define a VAR_EXPECTATION_MODEL
+** ------------------------------
+**
+** model_name:             the name of the VAR_EXPECTATION_MODEL (mandatory).
+** auxiliary_model_name:   the name of the VAR model used for the expectations (mandatory).
+** variable:               the name of the variable to be forecasted (mandatory).
+** horizon:                the horizon forecast (mandatory).
+** discount:               the discount factor, which can be a value or a declared parameter (default is 1.0, no discounting).
+**
+**
+** The `horizon` parameter can be an integer in which case the (discounted) `horizon` step ahead forecast
+** is computed using the VAR model `var_model_name`. Alternatively, `horizon` can be a range. In this case
+** VAR_EXPECTATION_MODEL returns a discounted sum of expected values. If `horizon` is set equal to the range
+** 0:Inf, then VAR_EXPECTATION_MODEL computes:
+**
+**                                       ∑ βʰ Eₜ[yₜ₊ₕ]
+**
+** where the sum is over h=0,…,∞ and the conditional expectations are computed with VAR model `var_model_name`.
+*/
+
+var_expectation_model(model_name = varexp, expression = x1/100-alpha*x2, auxiliary_model_name = toto, horizon = 15:50, discount = beta)  ;
+
+
+model;
+
+[name='eq:x1', data_type='nonstationary']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1))+a_x1_0_*(x2(-1)-x2bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2', data_type='nonstationary']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar', data_type='nonstationary']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar', data_type='nonstationary']
+x2bar = x2bar(-1) + ex2bar;
+
+foo = .5*foo(-1) + var_expectation(varexp);
+end;
+
+// Initialize the VAR expectation model, will build the companion matrix of the VAR.
+var_expectation.initialize('varexp')
+
+// Update VAR_EXPECTATION reduced form parameters
+var_expectation.update('varexp');
+
+weights = M_.params(M_.var_expectation.varexp.param_indices);
+
+if ~all(weights(1:6)) || ~all(weights(9:10)) || weights(7) || weights(8) || weights(11) || weights(12)
+   error('Wrong reduced form parameter for VAR_EXPECTATION_MODEL')
+end
\ No newline at end of file
diff --git a/tests/write/example1.mod b/tests/write/example1.mod
new file mode 100644
index 0000000000000000000000000000000000000000..8ba9f85a37ec9ea1c49e252757f1a8877e820d81
--- /dev/null
+++ b/tests/write/example1.mod
@@ -0,0 +1,89 @@
+// --+ options: json=compute, stochastic +--
+
+var x1 x2 x1bar x2bar z y x;
+
+varexo ex1
+       ex2
+       ex1bar
+       ex2bar
+       ez
+       ey   (status='observed') // This shock is observed...
+       ex   (status='observed') // ... this one also. Other shocks will be  considered as non observed.
+;
+
+parameters
+       rho_1 rho_2 rho_3 rho_4
+       a_x1_0 a_x1_1 a_x1_2 a_x1_x2_1 a_x1_x2_2
+	   a_x2_0 a_x2_1 a_x2_2 a_x2_x1_1 a_x2_x1_2
+	   e_c_m c_z_1 c_z_2 beta
+       lambda;
+
+rho_1 =  .9;
+rho_2 = -.2;
+rho_3 =  .4;
+rho_4 = -.3;
+
+
+a_x1_0 =  -.9;
+a_x1_1 =  .4;
+a_x1_2 =  .3;
+a_x1_x2_1 = .1;
+a_x1_x2_2 = .2;
+
+a_x2_0 =  -.9;
+a_x2_1 =   .2;
+a_x2_2 =  -.1;
+a_x2_x1_1 = -.1;
+a_x2_x1_2 = .2;
+
+beta  =  .2;
+e_c_m =  .5;
+c_z_1 =  .2;
+c_z_2 = -.1;
+
+lambda = 0.5; // Share of optimizing agents.
+
+trend_component_model(model_name=toto, eqtags=['eq:x1', 'eq:x2', 'eq:x1bar', 'eq:x2bar'], targets=['eq:x1bar', 'eq:x2bar']);
+
+pac_model(auxiliary_model_name=toto, discount=beta, model_name=pacman);
+
+model;
+
+[name='eq:y']
+y = rho_1*y(-1) + rho_2*y(-2) + ey;
+
+[name='eq:x']
+x = rho_3*x(-1) + rho_4*x(-2) + ex;
+
+[name='eq:x1']
+diff(x1) = a_x1_0*(x1(-1)-x1bar(-1)) + a_x1_1*diff(x1(-1)) + a_x1_2*diff(x1(-2)) + a_x1_x2_1*diff(x2(-1)) + a_x1_x2_2*diff(x2(-2)) + ex1;     
+
+[name='eq:x2']
+diff(x2) = a_x2_0*(x2(-1)-x2bar(-1)) + a_x2_1*diff(x1(-1)) + a_x2_2*diff(x1(-2)) + a_x2_x1_1*diff(x2(-1)) + a_x2_x1_2*diff(x2(-2)) + ex2;     
+
+[name='eq:x1bar']
+x1bar = x1bar(-1) + ex1bar;
+
+[name='eq:x2bar']
+x2bar = x2bar(-1) + ex2bar;
+
+[name='zpac']
+diff(z) = lambda*(e_c_m*(x1(-1)-z(-1)) + c_z_1*diff(z(-1))  + c_z_2*diff(z(-2)) + pac_expectation(pacman)) + (1-lambda)*( y + x) + ez;
+
+end;
+
+shocks;
+    var ex1 = 1.0;
+    var ex2 = 1.0;
+    var ex1bar = 1.0;
+    var ex2bar = 1.0;
+    var ez = 1.0;
+    var ey = 0.1;
+    var ex = 0.1;
+end;
+
+verbatim;
+  if ~isequal(M_.observed_exo_names, {'ey'; 'ex'})
+    error()
+  end
+end;