Merge remote-tracking branch 'community/master' into enterprise

time-shift
Sébastien Villemot 2019-09-26 16:54:27 +02:00
commit cbb59fe6f8
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
881 changed files with 4730727 additions and 70092 deletions

View File

@ -1,6 +1,7 @@
((nil .
((c-file-style . "gnu")
(indent-tabs-mode . nil)
(fill-column . 79)))
(c-mode . (c-basic-offset 2))
(makefile-mode . ((indent-tabs-mode . t))))
((c-mode . ((indent-tabs-mode . nil)
(c-file-style . "gnu")))
(c++-mode . ((indent-tabs-mode . nil)
(c-file-style . "gnu")))
(makefile-mode . ((indent-tabs-mode . t)))
(octave-mode . ((indent-tabs-mode . nil)
(octave-block-offset . 4))))

109
.gitignore vendored
View File

@ -11,13 +11,12 @@
\#*\#
TAGS
*.mat
*.xls
*.xlsx
# Build system rules
.deps
Makefile
Makefile.in
confdefs.h
configure
config.log
config.status
@ -56,48 +55,18 @@ checksum
*.bbl
*.blg
*.lof
/doc/dynare.html
/doc/dynare.info
/doc/dynare.info-1
/doc/dynare.info-2
/doc/dynare.info-3
/doc/dynare.cp
/doc/dynare.fn
/doc/dynare.fns
/doc/dynare.vrs
/doc/dynare.ky
/doc/dynare.pg
/doc/dynare.tp
/doc/dynare.vr
/doc/dynare.t2p/*
/doc/texinfo.tex
/doc/version.texi
/doc/mdate-sh
/doc/stamp-vti
/doc/manual/build
/doc/manual/utils/version.py
/doc/manual/utils/__pycache__/*
!/doc/guide.bbl
!/doc/userguide/P_ModStruct3.pdf
!/doc/userguide/P_MH2.pdf
!/doc/userguide/P_flowest.pdf
!/doc/userguide/P_ModStruct4.pdf
!/doc/userguide/Graphics/DynareFigures.key/droppedImage-2.pdf
!/doc/userguide/Graphics/DynareFigures.key/droppedImage.pdf
!/doc/userguide/Graphics/DynareFigures.key/droppedImage-1.pdf
!/doc/userguide/Graphics/DynareTitle.pdf
!/doc/userguide/P_ModStruct5.pdf
!/doc/userguide/P_DynareStruct2.pdf
!/doc/userguide/P_SchorfMod.pdf
!/doc/userguide/P_ModStruct2.pdf
!/doc/userguide/P_ShockModel2.pdf
!/doc/parallel/AvenueParadigm.pdf
!/doc/parallel/iVaNo_*.pdf
!/doc/parallel/netbook_*.pdf
!/doc/parallel/quest_*.pdf
!/doc/parallel/RWMH_quest1_*.pdf
!/doc/parallel/waitbars*.pdf
doc/m2html
doc/internals/*.html
doc/internals/ltxpng
mex/build/matlab/run_m2html.m
# MATLAB dir
/matlab/preprocessor*
@ -108,7 +77,6 @@ mex/build/matlab/run_m2html.m
# DLL rules
*.mex
*.dll
*.oct
*.mexglx
*.mexa64
@ -119,21 +87,22 @@ mex/build/matlab/run_m2html.m
/mex/matlab/
/mex/octave/
# Symbolic links created for building MEX files
/mex/build/matlab/*/*.c
/mex/build/matlab/*/*.cc
/mex/build/octave/*/*.c
/mex/build/octave/*/*.cc
# Dynare++
/dynare++/integ/cc/*.cpp
/dynare++/integ/cc/*.h
/dynare++/integ/cc/main.tex
/dynare++/integ/src/quadrature-points.dSYM/
/dynare++/src/dynare++.dSYM/
/dynare++/integ/src/quadrature-points
/dynare++/integ/src/quadrature-points.exe
/dynare++/integ/testing/tests
/dynare++/kord/*.cpp
!/dynare++/kord/tests.cpp
/dynare++/kord/*.h
/dynare++/kord/main.tex
/dynare++/integ/testing/tests.exe
/dynare++/kord/tests
/dynare++/kord/tests.exe
/dynare++/kord/out.txt
/dynare++/sylv/testing/*.mm
/dynare++/sylv/testing/tests
/dynare++/sylv/testing/tests.exe
/dynare++/parser/cc/*_ll.cc
@ -144,38 +113,39 @@ mex/build/matlab/run_m2html.m
/dynare++/src/dynglob_ll.cc
/dynare++/src/dynglob_tab.cc
/dynare++/src/dynglob_tab.hh
/dynare++/tl/cc/*.cpp
/dynare++/tl/cc/*.h
/dynare++/tl/cc/main.tex
/dynare++/tl/testing/tests
/dynare++/tl/testing/tests.exe
/dynare++/tests/*.jnl
/dynare++/tests/*.m
/dynare++/tests/*.mat
/dynare++/tests/*.dump
!/dynare++/extern/R/Makefile
# Windows
/windows/dynare-version.nsi
# Estimation DLL tests
/mex/sources/estimation/tests/test-dr
/mex/sources/estimation/tests/test-dr.exe
/mex/sources/estimation/tests/testModelSolution
/mex/sources/estimation/tests/testModelSolution.exe
/mex/sources/estimation/tests/testInitKalman
/mex/sources/estimation/tests/testInitKalman.exe
/mex/sources/estimation/tests/testKalman
/mex/sources/estimation/tests/testKalman.exe
/mex/sources/estimation/tests/testPDF
/mex/sources/estimation/tests/testPDF.exe
/mex/sources/estimation/libmat/tests/test-qr
/mex/sources/estimation/libmat/tests/test-qr.exe
/mex/sources/estimation/libmat/tests/test-gsd
/mex/sources/estimation/libmat/tests/test-gsd.exe
/mex/sources/estimation/libmat/tests/test-lu
/mex/sources/estimation/libmat/tests/test-lu.exe
/mex/sources/estimation/libmat/tests/test-repmat
/mex/sources/estimation/libmat/tests/test-repmat.exe
!/windows/Makefile
!/windows/deps/Makefile
windows/deps/lib32/
windows/deps/lib64/
windows/deps/lib32-msys2/
windows/deps/lib64-msys2/
windows/deps/matlab32/
windows/deps/matlab64/
windows/deps/mingw32/
windows/deps/mingw64/
windows/deps/octave32/
windows/deps/octave64/
windows/deps/sources32/
windows/deps/sources64/
windows/deps/tarballs/
windows/exe/
windows/7z/
windows/zip/
dynare++/32-bit/
dynare++/64-bit/
# MacOS stuff
.DS_Store
macOS/pkg/
# Emacs stuff
scripts/dynare.elc
@ -185,6 +155,7 @@ scripts/dynare.elc
/contrib/ms-sbvar/*.dat
/contrib/ms-sbvar/sbvar_commandline
/contrib/ms-sbvar/sbvar_init_file
!/contrib/ms-sbvar/Makefile
/tests/ms-sbvar/*.tmp
# Reporting
@ -199,3 +170,5 @@ octave-workspace
# VERSION generated file
VERSION
matlab/supported_octave_version.m

View File

@ -2,22 +2,47 @@ variables:
GIT_SUBMODULE_STRATEGY: normal
TERM: linux
# 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 on a tag: use the tag
# + if on master: use 4.6-unstable-$TIMESTAMP-$COMMIT
# + on another branch: use $BRANCH-$TIMESTAMP-$COMMIT
# - if in a personal repository: use $USER-$TIMESTAMP-$COMMIT
before_script:
- wget http://www.dynare.org/x13/x13.zip
- unzip x13.zip
- cp -r binaries/linux matlab/modules/dseries/externals/x13
- '[[ -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.6-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 ]] && export VERSION=$CI_PROJECT_NAMESPACE-$(date +%F-%H%M)-$CI_COMMIT_SHORT_SHA'
stages:
- build
- test_and_pkg
- deploy
build_binaries:
stage: build
script:
- autoreconf -si
- './configure --with-matlab=$(dirname $(dirname $(readlink -f `which matlab`))) MATLAB_VERSION=$(echo version | matlab -nodesktop -nodisplay -nosplash 2>/dev/null | sed -En "/ans\ =/!d;n;n;s/^[^0-9]*([0-9]+\.[0-9]+).*$/\1/;p")'
- './configure --with-matlab=$(dirname $(dirname $(readlink -f $(which matlab)))) MATLAB_VERSION=$(echo version | matlab -nodesktop -nodisplay -nosplash 2>/dev/null | sed -En "/ans\ =/!d;n;n;s/^[^0-9]*([0-9]+\.[0-9]+).*$/\1/;p")'
- make -j $(nproc) LN_S="cp -p"
artifacts:
paths:
- matlab/preprocessor*/*
- mex/octave/
- mex/matlab/
- dynare++/parser/cc/*_tab.cc
- dynare++/parser/cc/*_tab.hh
- dynare++/parser/cc/*_ll.cc
- dynare++/src/*_tab.cc
- dynare++/src/*_tab.hh
- dynare++/src/*_ll.cc
- dynare++/*/*.o
- dynare++/*/*.a
- dynare++/*/*/*.o
- dynare++/*/*/*.a
- dynare++/integ/src/quadrature-points
- dynare++/src/dynare++
expire_in: 1 week
@ -26,34 +51,102 @@ build_doc:
script:
- autoreconf -si
- ./configure --disable-matlab --disable-octave
- make -j $(nproc) info pdf html
- make -j $(nproc) pdf html
artifacts:
paths:
- doc/dynare.info*
- doc/dynare.html
- doc/dynare.pdf
- doc/manual/build/
- doc/*.pdf
- doc/*/*.pdf
- dynare++/doc/*.pdf
- preprocessor/doc/*/*.pdf
expire_in: 1 week
testsuite_matlab:
stage: test
pkg_source:
stage: test_and_pkg
script:
- 'for f in configure.ac preprocessor/configure.ac mex/build/matlab/configure.ac mex/build/octave/configure.ac; do sed -i "s/^AC_INIT(\[\(.*\)\],\s*\[\(.*\)\])/AC_INIT([\1], [$VERSION])/" $f; done'
- autoreconf -si
- './configure --disable-octave --with-matlab=$(dirname $(dirname $(readlink -f `which matlab`))) MATLAB_VERSION=$(echo version | matlab -nodesktop -nodisplay -nosplash 2>/dev/null | sed -En "/ans\ =/!d;n;n;s/^[^0-9]*([0-9]+\.[0-9]+).*$/\1/;p")'
- make -j $(($(nproc) * 3 / 4)) -C tests check-matlab
- ./configure
- make dist
artifacts:
paths:
- dynare-*.tar.xz
expire_in: 1 week
dependencies: []
pkg_windows:
stage: test_and_pkg
script:
- ln -s ~/tarballs windows/deps/
- make -C windows
cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- windows/deps/sources32/
- windows/deps/sources64/
- windows/deps/lib32/
- windows/deps/lib64/
# We do not cache lib{32,64}-msys2, mingw{32,64}, octave{32,64} and
# matlab{32,64}, because those are simply extracted from a tarball. It
# would be a waste of space and of (re-compression) time.
artifacts:
paths:
- windows/exe/*
- windows/7z/*
- windows/zip/*
expire_in: 1 week
dependencies:
- build_doc
pkg_macOS:
stage: test_and_pkg
script:
- make -C macOS
tags:
- macOS
artifacts:
paths:
- macOS/pkg/*
expire_in: 1 week
dependencies:
- build_doc
.test_matlab_template:
stage: test_and_pkg
artifacts:
paths:
- tests/*.m.log
- tests/*.m.trs
- tests/*/*.m.log
- tests/*/*.m.trs
- tests/*/*.jnl
- tests/*/*/*.m.log
- tests/*/*/*.m.trs
- tests/*/*/*.jnl
- tests/run_test_matlab_output.txt
when: always
dependencies:
- build_binaries
.testsuite_octave_template:
stage: test
test_matlab:
extends: .test_matlab_template
script:
- autoreconf -si
- './configure --disable-octave --with-matlab=$(dirname $(dirname $(readlink -f $(which matlab)))) MATLAB_VERSION=$(echo version | matlab -nodesktop -nodisplay -nosplash 2>/dev/null | sed -En "/ans\ =/!d;n;n;s/^[^0-9]*([0-9]+\.[0-9]+).*$/\1/;p")'
- make -j $(($(nproc) * 3 / 4)) -C tests check-matlab
test_old_matlab:
extends: .test_matlab_template
script:
- autoreconf -si
- './configure --disable-octave --with-matlab=/usr/local/MATLAB/R2009b MATLAB_VERSION=R2009b'
- make -C mex/build/matlab clean
- make -j $(nproc) -C mex/build/matlab
- make -j $(($(nproc) * 3 / 4)) -C tests check-matlab
when: manual
test_octave:
stage: test_and_pkg
variables:
OPENBLAS_NUM_THREADS: 1
script:
@ -66,22 +159,65 @@ testsuite_matlab:
- tests/*.o.trs
- tests/*/*.o.log
- tests/*/*.o.trs
- tests/*/*.jnl
- tests/*/*/*.o.log
- tests/*/*/*.o.trs
- tests/*/*/*.jnl
- tests/run_test_octave_output.txt
when: always
dependencies:
- build_binaries
testsuite_octave_auto:
extends: .testsuite_octave_template
only:
- tags
- schedules
testsuite_octave_manual:
extends: .testsuite_octave_template
except:
- tags
- schedules
when: manual
test_dynare++:
stage: test_and_pkg
script:
- autoreconf -si
- ./configure --disable-matlab --disable-octave
- touch dynare++/parser/cc/*_tab.cc dynare++/parser/cc/*_tab.hh dynare++/parser/cc/*_ll.cc dynare++/src/*_tab.cc dynare++/src/*_tab.hh dynare++/src/*_ll.cc
- touch dynare++/*/*.o dynare++/*/*/*.o
- touch dynare++/*/*.a dynare++/*/*/*.a
- touch dynare++/integ/src/quadrature-points dynare++/src/dynare++
- make -C dynare++ check
dependencies:
- build_binaries
artifacts:
paths:
- dynare++/kord/out.txt
- dynare++/tests/*.jnl
- dynare++/tests/*.m
- dynare++/tests/*.mat
- dynare++/tests/*.dump
deploy_manual_unstable:
stage: deploy
only:
- master@Dynare/dynare
tags:
- restricted
dependencies:
- build_doc
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/
deploy_snapshot_unstable:
stage: deploy
only:
- master@Dynare/dynare
tags:
- restricted
dependencies:
- pkg_source
- pkg_windows
- pkg_macOS
script:
- f=(windows/exe/*) && osslsigncode sign -pkcs12 ~/dynare-object-signing.p12 -n Dynare -i https://www.dynare.org -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

16
.gitmodules vendored
View File

@ -1,31 +1,31 @@
[submodule "contrib/ms-sbvar/utilities_dw"]
path = contrib/ms-sbvar/utilities_dw
url = https://git.dynare.org/contrib/utilities_dw.git
url = ../../contrib/utilities_dw.git
[submodule "contrib/ms-sbvar/switch_dw"]
path = contrib/ms-sbvar/switch_dw
url = https://git.dynare.org/contrib/switch_dw.git
url = ../../contrib/switch_dw.git
[submodule "contrib/ms-sbvar/TZcode"]
path = contrib/ms-sbvar/TZcode
url = https://git.dynare.org/contrib/TZcode.git
url = ../../contrib/TZcode.git
[submodule "contrib/dmm"]
path = contrib/dmm
url = https://git.dynare.org/contrib/dmm.git
url = ../../contrib/dmm.git
[submodule "matlab/utilities/tests"]
path = matlab/utilities/tests
url = https://git.dynare.org/Dynare/m-unit-tests.git
url = ../../Dynare/m-unit-tests.git
[submodule "matlab/particles"]
path = matlab/particles
url = https://git.dynare.org/Dynare/particles.git
url = ../../Dynare/particles.git
[submodule "matlab/modules/dseries"]
path = matlab/modules/dseries
url = ../../Enterprise/dseries.git
branch = enterprise
[submodule "matlab/modules/reporting"]
path = matlab/modules/reporting
url = https://git.dynare.org/Dynare/reporting.git
url = ../../Dynare/reporting.git
[submodule "contrib/jsonlab"]
path = contrib/jsonlab
url = https://github.com/fangq/jsonlab.git
[submodule "preprocessor"]
path = preprocessor
url = https://git.dynare.org/Dynare/preprocessor.git
url = ../../Dynare/preprocessor.git

View File

@ -45,7 +45,7 @@ So, now you've reported the bug or asked for an enhancemnt by creating a GitHub
Now, if you want to go the extra mile, you'll volunteer to contribute code to fix the GitHub issue you created above. Once we've agreed that you'll do it, please do the following:
1. Clone the Dynare repository:
* `git clone https://git.dynare.org/Dynare/dynare.git`
* `git clone --recurse-submodules https://git.dynare.org/Dynare/dynare.git`
1. [Fork the Dynare repository](https://help.github.com/articles/fork-a-repo)
1. Change into the `dynare` folder and add the forked repository as a remote:
* `cd dynare`

View File

@ -28,23 +28,21 @@ EXTRA_DIST = \
CONTRIBUTING.md \
windows/dynare.nsi \
windows/README.txt \
osx \
macOS \
examples \
scripts \
.dir-locals.el
all-local: preprocessor/src/dynare_m
{ \
if [ -z "`file preprocessor/src/dynare_m | grep x86.64`" ]; then \
ARCH="32"; \
else \
all-local: preprocessor/src/dynare_m$(EXEEXT)
if file preprocessor/src/dynare_m$(EXEEXT) | grep -q x86.64; then \
ARCH="64"; \
else \
ARCH="32"; \
fi; \
mkdir -p $(abs_srcdir)/matlab/preprocessor$$ARCH; \
$(LN_S) -f $(abs_srcdir)/preprocessor/src/dynare_m $(abs_srcdir)/matlab/preprocessor$$ARCH; \
mkdir -p $(abs_srcdir)/julia/preprocessor$$ARCH ; \
$(LN_S) -f $(abs_srcdir)/preprocessor/src/dynare_m $(abs_srcdir)/julia/preprocessor$$ARCH; \
}
mkdir -p $(abs_srcdir)/matlab/preprocessor$$ARCH && \
$(LN_S) -f $(abs_builddir)/preprocessor/src/dynare_m$(EXEEXT) $(abs_srcdir)/matlab/preprocessor$$ARCH && \
mkdir -p $(abs_srcdir)/julia/preprocessor$$ARCH && \
$(LN_S) -f $(abs_builddir)/preprocessor/src/dynare_m$(EXEEXT) $(abs_srcdir)/julia/preprocessor$$ARCH
dist-hook:
rm -rf `find $(distdir)/matlab $(distdir)/examples -name *~`
@ -61,15 +59,13 @@ install-exec-local:
cp -r matlab $(DESTDIR)$(pkglibdir)
find $(DESTDIR)$(pkglibdir) -name LICENSE.md -delete
rm -rf $(DESTDIR)$(pkglibdir)/matlab/preprocessor*
{ \
if [ -z "`file preprocessor/src/dynare_m | grep x86.64`" ]; then \
ARCH="32"; \
else \
if file preprocessor/src/dynare_m | grep -q x86.64; then \
ARCH="64"; \
else \
ARCH="32"; \
fi; \
mkdir -p $(DESTDIR)$(pkglibdir)/matlab/preprocessor$$ARCH; \
cp preprocessor/src/dynare_m $(DESTDIR)$(pkglibdir)/matlab/preprocessor$$ARCH; \
}
mkdir -p $(DESTDIR)$(pkglibdir)/matlab/preprocessor$$ARCH && \
cp preprocessor/src/dynare_m $(DESTDIR)$(pkglibdir)/matlab/preprocessor$$ARCH
uninstall-local:
rm -f $(DESTDIR)$(bindir)/dynare++

77
NEWS
View File

@ -1,3 +1,80 @@
Announcement for Dynare 4.5.7 (on 2019-02-06)
=============================================
We are pleased to announce the release of Dynare 4.5.7.
This is a bugfix release.
The Windows packages are already available for download at:
http://www.dynare.org/download/dynare-stable
The Mac and GNU/Linux packages (for Debian and Ubuntu LTS) should follow soon.
This release is compatible with MATLAB versions 7.5 (R2007b) to 9.4 (R2018b)
and with GNU Octave versions 4.4.1.
Here is a list of the problems identified in version 4.5.6 and that have been
fixed in version 4.5.7:
- The mex-file conducting the QZ decomposition erroneously applied
the `qz_criterium` to the square absolute value of eigenvalues
instead of the absolute value itself (as done in mjdgges.m and the
AIM solver).
- In pathological cases, `mode_compute=5` (`newrat`) might enter an
infinite loop.
- `discretionary_policy` might erroneously state that the derivatives
of the objective function are non-zero if there are NaN present.
- Dynare++, when conducting the QZ decomposition, erroneously applied
the `qz_criterium` to the square absolute value of eigenvalues
instead of the absolute value itself.
- Dynare++: IRFs were incorrectly computed.
- `dynare_sensitivity` did not display the figures of
`irf_calibration`, it only stored them on the disk.
- Scatter plots generated by `dynare_sensitivity` did not correctly
display LaTeX names.
- Parameter updating via steady state files did not correctly work in
case of using [static]/[dynamic] equation tags.
- Memory leaks in `k_order_pert` (used by higher order stochastic
simulations) could lead to crashes.
- Predetermined variables were not properly set when used in model
local variables.
- Posterior moment computation did not correctly update the
covariance matrix of exogenous shocks during posterior sampling.
- Dynare was crashing with a cryptic message if a non estimated
parameter was initialized in the `estimated_params_init` block.
- The `forecast` command crashed if the model was declared as linear
and contained deterministic exogenous variables.
- Block decomposition is broken when used in conjunction with
`varexo_det`.
- The model was not correctly specified when `identification` was run
without another stochastic command in the `.mod` file
(e.g. `estimation`, `stoch_simul`, etc.).
- Realtime annualized shock decompositions added the wrong steady state
value.
- `mh_recover` option crashed when using slice sampler.
- x-axis values in plots of moment restrictions were wrong for
autocovariances.
Announcement for Dynare 4.5.6 (on 2018-07-25)
=============================================

129
README.md
View File

@ -1,16 +1,16 @@
<a name="logo"/>
<div align="center">
<a href="http://www.dynare.org/" target="_blank">
<img src="http://www.dynare.org/img/dynare.png" alt="Dynare Logo"></img>
<a href="https://www.dynare.org/" target="_blank">
<img src="https://www.dynare.org/assets/images/logo/dlogo.svg" alt="Dynare Logo"></img>
</a>
</div>
# Dynare
Described on the homepage: <http://www.dynare.org/>
Described on the homepage: <https://www.dynare.org/>
Most users should use the precompiled package available for your OS, also
available via the Dynare homepage: <http://www.dynare.org/download/dynare-stable>.
Most users should use the precompiled package available for their OS, also
available via the Dynare homepage: <https://www.dynare.org/download/>.
# Contributions
@ -31,20 +31,26 @@ Here, we explain how to build from source:
This source can be retrieved in three forms:
- via git, at <https://git.dynare.org/Dynare/dynare.git>
- using the stable source archive of the latest Dynare version (currently 4.4) from <http://www.dynare.org/download/dynare-stable/>
- using a source snapshot of the unstable version, from <http://www.dynare.org/download/dynare-unstable/source-snapshot>
- using the stable source archive of the latest Dynare version from <https://www.dynare.org/download/>
- using a source snapshot of the unstable version, also from <https://www.dynare.org/download/>
Note that if you obtain the source code via git, you will need to install more tools (see below).
The first section of this page gives general instructions, which apply to all platforms. Then some specific platforms are discussed.
**Note:** Here, when we refer to 32-bit or 64-bit, we refer to the type of MATLAB installation, not the type of Windows installation. It is perfectly possible to run a 32-bit MATLAB on a 64-bit Windows: in that case, instructions for Windows 32-bit should be followed. To determine the type of your MATLAB installation, type:
**Note:** Here, when we refer to 32-bit or 64-bit, we refer to the type of
MATLAB or Octave installation, not the type of operating system installation.
For example, it is perfectly possible to run a 32-bit MATLAB on a 64-bit
Windows: in that case, instructions for Windows 32-bit should be followed. To
determine the type of your MATLAB/Octave installation, type:
```matlab
>> computer
```
at the MATLAB prompt: if it returns `PCWIN64`, `GLNX64` or `MACI64`, then you
have a 64-bit MATLAB; if it returns `PCWIN`, `MACI` or `GLNX`, then you have a
32-bit MATLAB.
at the MATLAB/Octave prompt. Under MATLAB, if it returns `PCWIN64`, `GLNX64` or
`MACI64`, then it is a 64-bit MATLAB; if it returns `PCWIN`, `MACI` or `GLNX`,
then it is a 32-bit MATLAB. Under Octave, if it returns a string that begins
with `x86_64`, it is a 64-bit Octave; if the strings begins with `i686`, it is
a 32-bit Octave.
**Contents**
@ -60,29 +66,26 @@ have a 64-bit MATLAB; if it returns `PCWIN`, `MACI` or `GLNX`, then you have a
A number of tools and libraries are needed in order to recompile everything. You don't necessarily need to install everything, depending on what you want to compile.
- A POSIX compliant shell and an implementation of Make (mandatory)
- The [GNU Compiler Collection](http://gcc.gnu.org/), with gcc, g++ and gfortran (mandatory)
- The [GNU Compiler Collection](http://gcc.gnu.org/), version 8 or later, with
gcc, g++ and gfortran (mandatory)
- MATLAB (if you want to compile the MEX for MATLAB)
- [GNU Octave](http://www.octave.org), with the development headers (if you
want to compile the MEX for Octave)
- [Boost libraries](http://www.boost.org), version 1.36 or later (with the filesystem library compiled)
- [Bison](http://www.gnu.org/software/bison/), version 3.0 or later (only if you get the source through Git)
- [Boost libraries](http://www.boost.org), version 1.36 or later
- [Bison](http://www.gnu.org/software/bison/), version 3.2 or later (only if you get the source through Git)
- [Flex](http://flex.sourceforge.net/), version 2.5.4 or later (only if you get the source through Git)
- [Autoconf](http://www.gnu.org/software/autoconf/), version 2.62 or later (only if you get the source through Git) (see [Installing an updated version of Autoconf in your own directory, in GNU/Linux](http://www.dynare.org/DynareWiki/AutoMake))
- [Automake](http://www.gnu.org/software/automake/), version 1.11.2 or later (only if you get the source through Git) (see [Installing an updated version of AutoMake in your own directory, in GNU/Linux](http://www.dynare.org/DynareWiki/AutoMake))
- [CWEB](http://www-cs-faculty.stanford.edu/%7Eknuth/cweb.html), with its tools
`ctangle` and `cweave` (only if you want to build the k-order DLL or Dynare++, and get the source through Git)
- [Autoconf](http://www.gnu.org/software/autoconf/), version 2.62 or later (only if you get the source through Git)
- [Automake](http://www.gnu.org/software/automake/), version 1.11.2 or later (only if you get the source through Git)
- An implementation of BLAS and LAPACK: either [ATLAS](http://math-atlas.sourceforge.net/), [OpenBLAS](http://xianyi.github.com/OpenBLAS/), Netlib ([BLAS](http://www.netlib.org/blas/), [LAPACK](http://www.netlib.org/lapack/)) or [MKL](http://software.intel.com/en-us/intel-mkl/) (only if you want to build Dynare++)
- An implementation of [POSIX Threads](http://en.wikipedia.org/wiki/POSIX_Threads) (optional, for taking advantage of multi-core)
- [MAT File I/O library](http://sourceforge.net/projects/matio/) (if you want to compile Markov-Switching code, the estimation DLL, k-order DLL and Dynare++)
- [MAT File I/O library](http://sourceforge.net/projects/matio/), version 1.5 or later (if you want to compile Markov-Switching code, the estimation DLL, k-order DLL and Dynare++)
- [SLICOT](http://www.slicot.org) (if you want to compile the Kalman steady state DLL)
- [GSL library](http://www.gnu.org/software/gsl/) (if you want to compile Markov-Switching code)
- A decent LaTeX distribution (if you want to compile PDF documentation). The following extra components may be needed:
- [Eplain](http://www.tug.org/eplain/) TeX macros (only if you want to build Dynare++ source documentation)
- [Beamer](http://latex-beamer.sourceforge.net/) (for some PDF presentations)
- A decent LaTeX distribution (if you want to compile PDF documentation),
ideally with Beamer
- For building the reference manual:
- [GNU Texinfo](http://www.gnu.org/software/texinfo/)
- [Latex2HTML](http://www.latex2html.org), if you want nice mathematical formulas in HTML output
- [Doxygen](http://www.stack.nl/%7Edimitri/doxygen/) (if you want to build Dynare preprocessor source documentation)
- [Sphinx](http://www.sphinx-doc.org/)
- [MathJax](https://www.mathjax.org/)
- [Doxygen](http://www.stack.nl/%7Edimitri/doxygen/) (if you want to build Dynare preprocessor source documentation)
- For Octave, the development libraries corresponding to the UMFPACK packaged with Octave
### Preparing the sources
@ -91,7 +94,7 @@ If you have downloaded the sources from an official source archive or the source
If you want to use Git, do the following from a terminal:
git clone --recursive https://git.dynare.org/Dynare/dynare.git
git clone --recurse-submodules https://git.dynare.org/Dynare/dynare.git
cd dynare
autoreconf -si
@ -105,28 +108,39 @@ Simply launch the configure script from a terminal:
```
If you have MATLAB, you need to indicate both the MATLAB location and version. For example, on GNU/Linux:
```
./configure --with-matlab=/usr/local/MATLAB/R2013a MATLAB_VERSION=8.1
./configure --with-matlab=/usr/local/MATLAB/R2019a MATLAB_VERSION=9.6
```
Note that the MATLAB version can also be specified via the MATLAB family product release (R2009a, R2008b, ...).
Note that the MATLAB version can also be specified via the MATLAB family product release (R2019a, R2018b, …).
Alternatively, you can disable the compilation of MEX files for MATLAB with the `--disable-matlab` flag, and MEX files for Octave with `--disable-octave`.
You may need to specify additional options to the configure script, see the platform specific instructions below.
You may need to specify additional options to the configure script, see the
output of the `--help` option, and also the platform specific instructions
below.
Note that if you don't want to compile the C/C++ programs with debugging information, you can specify the `CFLAGS` and `CXXFLAGS` variables to the configure script, such as:
```
./configure CFLAGS="-O3" CXXFLAGS="-O3"
```
To remove debugging information for MATLAB MEX functions, the analagous call would be:
To remove debugging information for MATLAB MEX functions, the analogous call would be:
```
./configure MATLAB_MEX_CFLAGS="-O3" MATLAB_MEX_CXXFLAGS="-O3"
```
If you want to give a try to the parallelized versions of some mex files (`A_times_B_kronecker_C` and `sparse_hessian_times_B_kronecker_C` used to get the reduced form of the second order approximation of the model) you can add the `--enable-openmp` flag, for instance:
If the configuration goes well, the script will tell you which components are
correctly configured and will be built.
Note that it is possible that some MEX files cannot be compiled, due to missing
build dependencies. If you find no way of installing the missing dependencies,
a workaround can be to give up on compiling these MEX files and rather use
slower implementations (in the MATLAB/Octave language) that are available under
the `matlab/missing/mex/` subdirectories. For example, if you fail to compile
the gensylv MEX, you can type the following at the MATLAB/Octave prompt before
running Dynare:
```matlab
addpath <DYNARE_ROOT>/matlab/missing/mex/gensylv
```
./configure --with-matlab=/usr/local/MATLAB/R2013a MATLAB_VERSION=8.1 --enable-openmp
```
If the configuration goes well, the script will tell you which components are correctly configured and will be built.
(where you need to replace `<DYNARE_ROOT>` with the full path to your Dynare copy).
### Building
@ -154,7 +168,7 @@ The Git source comes with unit tests (in the MATLAB functions) and integration t
make check
```
In the `tests` subfolder. If Dynare has been compiled against MATLAB and Octave, the tests will be run with MATLAB and Octave. Depending on
your PC, this can take several hours. It is possible to run the tests only with MATLAB:
the performance of your machine, this can take several hours. It is possible to run the tests only with MATLAB:
```
make check-matlab
```
@ -205,7 +219,7 @@ All the prerequisites are packaged:
- `build-essential` (for gcc, g++ and make)
- `gfortran`
- `liboctave-dev`
- `libboost-graph-dev` and `libboost-filesystem-dev`
- `libboost-graph-dev`
- `libgsl-dev`
- `libmatio-dev`
- `libslicot-dev` and `libslicot-pic`
@ -216,25 +230,25 @@ All the prerequisites are packaged:
- `automake`
- `texlive`
- `texlive-publishers` (for Econometrica bibliographic style)
- `texlive-extra-utils` (for CWEB)
- `texlive-formats-extra` (for Eplain)
- `texlive-latex-extra` (for fullpage.sty)
- `texlive-fonts-extra` (for ccicons)
- `texlive-latex-recommended`
- `texlive-science` (for amstex)
- `texinfo`
- `texlive-generic-extra` (for Sphinx)
- `lmodern` (for macroprocessor PDF)
- `latex2html`
- `python3-sphinx`
- `libjs-mathjax`
- `doxygen`
You can install them all at once with:
```
apt install build-essential gfortran liboctave-dev libboost-graph-dev libboost-filesystem-dev libgsl-dev libmatio-dev libslicot-dev libslicot-pic libsuitesparse-dev flex bison autoconf automake texlive texlive-publishers texlive-extra-utils texlive-formats-extra texlive-latex-extra texlive-fonts-extra texlive-latex-recommended texlive-science texinfo lmodern latex2html doxygen
apt install build-essential gfortran liboctave-dev libboost-graph-dev libgsl-dev libmatio-dev libslicot-dev libslicot-pic libsuitesparse-dev flex bison autoconf automake texlive texlive-publishers texlive-latex-extra texlive-fonts-extra texlive-latex-recommended texlive-science texlive-generic-extra lmodern python3-sphinx libjs-mathjax doxygen
```
## Windows
- Install [MSYS2](http://www.msys2.org) (pick the 64-bit version)
- Install [MSYS2](http://www.msys2.org) (pick the 64-bit version, unless you
have a 32-bit Windows, in which case see below)
- Run a MSYS MinGW 64-bit shell
- Update the system:
```
@ -247,18 +261,6 @@ pacman -Syu
```
pacman -S git autoconf automake-wrapper bison flex make tar texinfo mingw-w64-x86_64-gcc mingw-w64-x86_64-gcc-fortran mingw-w64-x86_64-boost mingw-w64-x86_64-gsl mingw-w64-x86_64-matio mingw-w64-x86_64-openblas
```
- **(Optional)** compile and install `ctangle`, needed for the k-order MEX file and for
Dynare++ (*i.e.* if you want to solve models at order ≥ 3)
```
wget ftp://ftp.cs.stanford.edu/pub/cweb/cweb.tar.gz
mkdir cweb
cd cweb
tar xf ../cweb.tar.gz
make ctangle
mkdir -p /usr/local/bin
cp ctangle.exe /usr/local/bin/
cd ..
```
- **(Optional)** compile and install SLICOT, needed for the `kalman_steady_state`
MEX file
```
@ -272,13 +274,13 @@ cd ..
```
- Clone and prepare the Dynare sources:
```
git clone --recursive https://git.dynare.org/Dynare/dynare.git
git clone --recurse-submodules https://git.dynare.org/Dynare/dynare.git
cd dynare
autoreconf -si
```
- Configure Dynare:
```
./configure --with-boost-system=boost_system-mt --with-boost-filesystem=boost_filesystem-mt --with-slicot=/usr/local --with-matlab=<…> MATLAB_VERSION=<…> --disable-octave
./configure --with-slicot=/usr/local --with-matlab=<…> MATLAB_VERSION=<…> --disable-octave
```
where the path and version of MATLAB are specified. Note that you should use
the MSYS2 notation and not put spaces in the MATLAB path, so you probably want
@ -306,10 +308,10 @@ currently not supported.
## macOS
To simply use a snapshot of Dynare, you have two choices. On MATLAB, you can
use the [snapshot build](http://www.dynare.org/snapshot/macosx/) provided by
use the [snapshot build](https://www.dynare.org/snapshot/macos/) provided by
Dynare. On Octave, you can simply install [Homebrew](https://brew.sh/) and run
```brew install dynare --HEAD``` (See the Install Dynare (unstable) section of
[this webpage](http://www.dynare.org/DynareWiki/InstallOnMacOSX) for more
[this webpage](https://archives.dynare.org/DynareWiki/InstallOnMacOSX) for more
details).
If you do not wish to use the snapshots provided by Dynare or Homebrew, follow
@ -327,9 +329,6 @@ compile. They should be entered at the command prompt in Terminal.app.
- `brew install automake bison flex boost fftw gcc gsl hdf5 libmatio metis veclibfort`
- **(Optional)** To compile Dynare mex files for use on Octave:
- `brew install octave`
- `brew install suite-sparse`
- **(Optional)** To compile Dynare++
- `brew install cweb`
- **(Optional)** To compile Dynare documentation
- Install the latest version of [MacTeX](http://www.tug.org/mactex/), deselecting the option to install Ghostscript
- `brew install doxygen latex2html`
@ -338,13 +337,13 @@ The following commands will download the Dynare source code and compile
it. They should be entered at the command prompt in Terminal.app from the
folder where you want Dynare installed.
- `git clone https://git.dynare.org/Dynare/dynare.git`
- `git clone --recurse-submodules https://git.dynare.org/Dynare/dynare.git`
- `cd dynare`
- `PATH="/usr/local/opt/bison/bin:/usr/local/opt/flex/bin:$PATH"`
- `autoreconf -si`
- `./configure --disable-octave --with-matlab=/Applications/MATLAB_R2017b.app MATLAB_VERSION=R2017b`, adjusting the MATLAB path and version to accord with your local installation. If you don't have MATLAB, simply type `./configure --disable-octave`
- `CC=gcc-9 CXX=g++-9 ./configure --disable-octave --with-matlab=/Applications/MATLAB_R2019a.app MATLAB_VERSION=R2019a --with-matio=/usr/local --with-gsl=/usr/local --with-slicot=/usr/local`, adjusting the MATLAB path and version to accord with your local installation. If you don't have MATLAB, simply remove `--with-matlab=/Applications/MATLAB_R2019a.app MATLAB_VERSION=R2019a` from the above command
- `make -j`
- **(Optional)** To then build mex files for Octave, run
- `cd mex/build/octave`
- `./configure CXXFLAGS="-std=c++0x"`
- `CC=gcc-9 CXX=g++-9 ./configure --with-matio=/usr/local --with-gsl=/usr/local --with-slicot=/usr/local LDFLAGS=-L/usr/local/lib`
- `make -j`

View File

@ -1,75 +0,0 @@
In branch extended-preprocessor, we develop a version of Dynare
preprocessor that produces C and Cuda routine that can be later
linked within another program.
* dynare_m options
- new option output=dynamic|first|second|third
- output=dynamic generates <fname>_dynamic
- output=first generates <fname>_first_derivatives
- output=second generates <fname>_first_derivatives and <fname>_second_derivatives
- output=third generates <fname>_first_derivatives,
<fname>_second_derivatives and <fname>_third_derivatives
- routine <fname>_static is always generated
- routine <fname>_steady_state is generated if the *.mod file contains a
steady_state_model block
- routine <fname>_auxiliary_variables_steady_state is always
generated but doesn't contain any instruction is the preprocessor
didn't add any auxiliary variable
* Functions
- <fname>_model: returns a structure containting fields describing
the model, analogous to the M_ structure in Dynare. This structure
is defined in dynare_model.h and must be accessible when compiling
the second stage program.
- <fname>_dynamic: the historical Dynare dynamic function, returns
residuals, first, second and third order derivatives of the model,
if needed.
- <fname>_static: the historical Dynare static function, returns
residuals of the static model
- <fname>_steady_state: a function computing the steady state of the
model, given the parameters. It comes from parsing a
steady_state_model block in the *.mod file. Currently, there is no provision for
calling a non-linear solver for a subset of equations/variables.
- <fname>_auxiliary_variables_steady_state: a function to compute the steady state
values of auxiliary variables automatically added by the
preprocessor
- <fname>_first_derivatives: returns the Jacobian of the model at the steady
state, given the
steady state. It is more efficient than <fname>_dynamic. Doesn't
exist in Dynare yet.
- <fname>_second_derivatives: returns the second order derivatives of
the model. There are as many rows as equations and as many column
as the square of the number of endogenous and exogenous
variables. The matrix is stored in compressed sparse row format. It
is more efficient than compressed column format as there many more
columns than rows and many columns are empty. Note that the
transpose of the second derivatives matrix in compressed column
format can be obtained directly from the same function by inverting
the role of the two index vectors.
- <fname>_third_derivatives: returns the third order derivatives of
the model. See above for the storage format of this matrix.
* Implementation
** C++ version
- the routines use C++ and classes from the STL
** Cuda version
- the routines have the __global__ keyword necessary to create CUDA
kernls
- vector addressing uses a stride parameter to allow for various
storage schemes on the device
* Changes with dynare-msdsge
- removed erasing previous files as all files should be always
written to faciliate application building
- added back creating variables with the parameter name (otherwise
it doesn't work in Matlab backend) TO BE FIXED
* Pre-processor
- in DynareMain2.cc, in main2() option output != none calls ModFile::write_external_files()
- in ModFile.cc, ModFile::writeExternalFiles() calls
- ModFile::writeModelCC()
- SteadyStateMode::writeSteadyStateFileCC()
- DynamicModel::writeDynamicFile()
- StaticModel::writeStaticFile()
- DynamicModel::writeResidualsCC()
- DynamicModel::writeParamsDerivativesFileCC()
- DynamicModel::writeFirstDerivativesCC()
- DynamicModel::writeSecondDerivativesCC_csr()
- DynamicModel::writeThirdDerivativesCC_csr()

View File

@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
dnl Copyright (C) 2009-2018 Dynare Team
dnl Copyright © 2009-2019 Dynare Team
dnl
dnl This file is part of Dynare.
dnl
@ -26,6 +26,7 @@ AC_CONFIG_SUBDIRS([preprocessor])
AC_PROG_CC
AC_PROG_CXX
AX_CXX_COMPILE_STDCXX_17
AC_CANONICAL_HOST
case ${host_os} in
@ -33,25 +34,23 @@ case ${host_os} in
# On Windows, we want Dynare++ to be statically linked
AM_LDFLAGS="-static"
AC_SUBST([AM_LDFLAGS])
have_windows="yes"
;;
*cygwin*)
AC_MSG_WARN([You are compiling for the Cygwin target. This means that the preprocessor will])
AC_MSG_WARN([not run from MATLAB unless you add the Cygwin DLL to the path.])
AC_MSG_WARN([This is probably not what you want. Consider using a MinGW cross-compiler.])
if test "x$F77" = "x"; then
if test -z "$F77"; then
# On Cygwin 1.7, g77 comes has version 3, and is not compatible with default gcc/g++ which has version 4
# And by default, the AC_PROG_F77 will pick up g77 if it is present (even if gfortran is also here)
F77=gfortran
fi
have_windows="yes"
;;
esac
# Use C++ for testing headers
AC_LANG([C++])
AM_CXXFLAGS="-Wall -Wno-parentheses"
AM_CXXFLAGS="-Wall -Wno-parentheses -Wold-style-cast"
AC_SUBST([AM_CXXFLAGS])
# If default 'ar' is not available, try to find one with a host prefix (see ticket #145)
@ -64,64 +63,33 @@ AX_PROG_LN_S
AC_PROG_MKDIR_P
# We need 1.36 because of unordered_{set,hash} used by Dynare++
AX_BOOST_BASE([1.36], [], [AC_MSG_ERROR([Can't find Boost >= 1.36])])
AX_CXX11_THREAD
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
AC_CHECK_HEADERS([boost/graph/adjacency_list.hpp], [], [AC_MSG_ERROR([Can't find Boost Graph Library])])
AC_CHECK_HEADERS([boost/algorithm/string/trim.hpp], [], [AC_MSG_ERROR([Can't find Boost String Library])])
AC_CHECK_HEADERS([boost/algorithm/string/split.hpp], [], [AC_MSG_ERROR([Can't find Boost String Library])])
AC_CHECK_HEADERS([boost/lexical_cast.hpp], [], [AC_MSG_ERROR([Can't find Boost Lexical Cast Header])])
CPPFLAGS="$CPPFLAGS_SAVED"
AM_PROG_LEX
# Don't use deprecated hash structures
AC_DEFINE([BOOST_NO_HASH], [], [Don't use deprecated STL hash structures])
AC_CHECK_PROG([YACC], [bison], [bison])
if test -z "$YACC"; then
unset YACC # AM_MISSING_PROG needs an unset variable: an empty variable won't do
AM_MISSING_PROG([YACC], [bison])
fi
# Check for libmatio, needed by Dynare++
AX_MATIO
AM_CONDITIONAL([HAVE_MATIO], [test "x$has_matio" = "xyes"])
AC_CHECK_PROG([MAKEINFO], [makeinfo], [makeinfo])
AC_CHECK_PROG([PDFTEX], [pdftex], [pdftex])
AM_CONDITIONAL([HAVE_PDFTEX], [test "x$PDFTEX" != "x"])
AC_CHECK_PROG([PDFETEX], [pdfetex], [pdfetex])
AM_CONDITIONAL([HAVE_PDFETEX], [test "x$PDFETEX" != "x"])
if test "x$PDFTEX" != "x"; then
AC_MSG_CHECKING([for eplain])
AX_TEX_TEST([\input eplain
\end
], [ax_tex_have_eplain])
AC_MSG_RESULT([$ax_tex_have_eplain])
fi
AM_CONDITIONAL([HAVE_EPLAIN], [test "x$ax_tex_have_eplain" = "xyes"])
AM_CONDITIONAL([HAVE_MATIO], [test "$has_matio" = yes])
AC_CHECK_PROG([PDFLATEX], [pdflatex], [pdflatex])
AM_CONDITIONAL([HAVE_PDFLATEX], [test "x$PDFLATEX" != "x"])
AM_CONDITIONAL([HAVE_PDFLATEX], [test -n "$PDFLATEX"])
AC_CHECK_PROG([BIBTEX], [bibtex], [bibtex])
AM_CONDITIONAL([HAVE_BIBTEX], [test "x$BIBTEX" != "x"])
AM_CONDITIONAL([HAVE_BIBTEX], [test -n "$BIBTEX"])
AC_CHECK_PROG([LATEX2HTML], [latex2html], [latex2html])
AM_CONDITIONAL([HAVE_LATEX2HTML], [test "x$LATEX2HTML" != "x"])
AC_CHECK_PROG([SPHINXBUILD], [sphinx-build], [sphinx-build])
AM_CONDITIONAL([HAVE_SPHINXBUILD], [test -n "$SPHINXBUILD"])
if test "x$PDFLATEX" != "x" -a "x$BIBTEX" != "x"; then
if test -n "$PDFLATEX" -a -n "$BIBTEX"; then
AX_LATEX_CLASS([beamer], [ax_latex_have_beamer])
fi
AM_CONDITIONAL([HAVE_BEAMER], [test "x$ax_latex_have_beamer" = "xyes"])
AC_CHECK_PROG([CTANGLE], [ctangle], [ctangle])
AM_CONDITIONAL([HAVE_CTANGLE], [test "x$CTANGLE" != "x"])
if test "x$CTANGLE" = "x"; then
unset CTANGLE # AM_MISSING_PROG needs an unset variable: an empty variable won't do
AM_MISSING_PROG([CTANGLE], [ctangle])
fi
AC_CHECK_PROG([CWEAVE], [cweave], [cweave])
AM_CONDITIONAL([HAVE_CWEAVE], [test "x$CWEAVE" != "x"])
AM_CONDITIONAL([HAVE_BEAMER], [test "$ax_latex_have_beamer" = yes])
AC_PROG_F77
AC_F77_LIBRARY_LDFLAGS
@ -133,25 +101,24 @@ case ${host_os} in
;;
esac
if test "x$F77" != "x"; then
if test -n "$F77"; then
AX_BLAS
AX_LAPACK
fi
AM_CONDITIONAL([HAVE_BLAS], [test x"$ax_blas_ok" = "xyes"])
AM_CONDITIONAL([HAVE_LAPACK], [test x"$ax_lapack_ok" = "xyes"])
AX_PTHREAD
AM_CONDITIONAL([HAVE_BLAS], [test "$ax_blas_ok" = yes])
AM_CONDITIONAL([HAVE_LAPACK], [test "$ax_lapack_ok" = yes])
AC_CONFIG_FILES([Makefile
VERSION
doc/Makefile
doc/manual/Makefile
doc/manual/utils/version.py
doc/parallel/Makefile
doc/internals/Makefile
doc/gsa/Makefile
doc/dseries-and-reporting/Makefile
tests/Makefile
matlab/dynare_version.m
windows/dynare-version.nsi
dynare++/Makefile
dynare++/parser/cc/Makefile
dynare++/sylv/Makefile
@ -168,56 +135,41 @@ AC_CONFIG_FILES([Makefile
dynare++/integ/testing/Makefile
dynare++/kord/Makefile
dynare++/src/Makefile
dynare++/tests/Makefile
mex/sources/Makefile
])
AC_ARG_ENABLE([matlab], AS_HELP_STRING([--disable-matlab], [disable compilation of MEX files for MATLAB]), [], [enable_matlab=yes])
if test "x$enable_matlab" = "xyes"; then
if test "$enable_matlab" = yes; then
AC_CONFIG_SUBDIRS([mex/build/matlab])
AX_MATLAB
AX_MATLAB_ARCH
if test "${MATLAB_ARCH}" = win32 -o "${MATLAB_ARCH}" = win64; then
MATLAB_BATCH_OPTIONS='-nosplash -automation -wait -sd "$(CURDIR)"'
else
MATLAB_BATCH_OPTIONS='-nosplash -nodisplay'
fi
AC_SUBST([MATLAB_BATCH_OPTIONS])
AX_MATLAB_BATCH_OPTIONS
fi
AM_CONDITIONAL([ENABLE_MATLAB], [test "x$enable_matlab" = "xyes"])
AM_CONDITIONAL([HAVE_CMD_LINE_MATLAB], [test "x$ax_enable_matlab" = "xyes" -a "x$have_windows" = "x"])
AM_CONDITIONAL([ENABLE_MATLAB], [test "$enable_matlab" = yes])
AM_CONDITIONAL([HAVE_MATLAB], [test "$ax_enable_matlab" = yes])
AC_ARG_ENABLE([octave], AS_HELP_STRING([--disable-octave], [disable compilation of MEX files for Octave]), [], [enable_octave=yes])
if test "x$enable_octave" = "xyes"; then
if test "$enable_octave" = yes; then
AC_CONFIG_SUBDIRS([mex/build/octave])
AC_CHECK_PROG([OCTAVE], [octave], [octave])
fi
AM_CONDITIONAL([ENABLE_OCTAVE], [test "x$enable_octave" = "xyes"])
AM_CONDITIONAL([HAVE_OCTAVE], [test "x$enable_octave" = "xyes" -a "x$OCTAVE" != "x"])
AM_CONDITIONAL([ENABLE_OCTAVE], [test "$enable_octave" = yes])
AM_CONDITIONAL([HAVE_OCTAVE], [test "$enable_octave" = yes -a -n "$OCTAVE"])
# Enable exporting of Org files
# The clean way would be to test for Emacs, Org-mode, latex, dvipng...
AC_ARG_ENABLE([org-export], AS_HELP_STRING([--enable-org-export], [enable exporting of Org files (requires Emacs, org-mode and other external programs)]))
AM_CONDITIONAL([ENABLE_ORG_EXPORT], [test "x$enable_org_export" != "x"])
AM_CONDITIONAL([ENABLE_ORG_EXPORT], [test -n "$enable_org_export"])
# Construct final output message
if test "x$ax_blas_ok" = "xyes" -a "x$ax_lapack_ok" = "xyes" -a "x$has_matio" = "xyes"; then
if test x"$ax_pthread_ok" = "xyes"; then
BUILD_DYNAREPLUSPLUS="yes"
else
BUILD_DYNAREPLUSPLUS="yes (without POSIX threads)"
fi
if test "$ax_blas_ok" = yes -a "$ax_lapack_ok" = yes -a "$has_matio" = yes; then
BUILD_DYNAREPLUSPLUS="yes"
else
BUILD_DYNAREPLUSPLUS="no (missing one of: BLAS, LAPACK, MatIO)"
fi
if test "x$CWEAVE" != "x" -a x"$PDFTEX" != "x" -a "x$ax_tex_have_eplain" = "xyes"; then
BUILD_DYNAREPLUSPLUS_SRCDOC="yes"
else
BUILD_DYNAREPLUSPLUS_SRCDOC="no (missing one of: cweave, pdftex, eplain)"
fi
if test "x$PDFLATEX" != "x" -a "x$ax_latex_have_beamer" = "xyes"; then
if test -n "$PDFLATEX" -a "$ax_latex_have_beamer" = yes; then
BUILD_BEAMER_DOC="yes"
else
BUILD_BEAMER_DOC="no (missing one of: pdflatex, beamer)"
@ -229,33 +181,27 @@ else
BUILD_OTHER_PDF_DOC="no (missing pdflatex)"
fi
if test "x$enable_org_export" != "x"; then
if test -n "$enable_org_export"; then
BUILD_DYNARE_INTERNAL_DOC="yes"
else
BUILD_DYNARE_INTERNAL_DOC="no (Org export not enabled)"
fi
if test "x$MAKEINFO" != "x"; then
BUILD_DYNARE_INFO="yes"
if test "x$LATEX2HTML" != "x"; then
BUILD_DYNARE_HTML_MANUAL="yes"
else
BUILD_DYNARE_HTML_MANUAL="yes (but with ugly math formulas, missing latex2html)"
fi
if test -n "$SPHINXBUILD"; then
BUILD_DYNARE_HTML_MANUAL="yes"
BUILD_DYNARE_PDF_MANUAL="yes"
else
BUILD_DYNARE_INFO="no (missing makeinfo)"
BUILD_DYNARE_HTML_MANUAL="no (missing makeinfo)"
BUILD_DYNARE_PDF_MANUAL="no (missing makeinfo)"
BUILD_DYNARE_HTML_MANUAL="no (missing sphinx-build)"
BUILD_DYNARE_PDF_MANUAL="no (missing sphinx-build)"
fi
if test "x$OCTAVE" != "x"; then
if test -n "$OCTAVE"; then
TESTSUITE_OCTAVE="yes"
else
TESTSUITE_OCTAVE="no"
fi
if test "x$ax_blas_ok" = "xyes" -a "x$ax_lapack_ok" = "xyes"; then
if test "$ax_blas_ok" = yes -a "$ax_lapack_ok" = yes; then
TESTSUITE_DYNAREPLUSPLUS="yes"
else
TESTSUITE_DYNAREPLUSPLUS="no"
@ -270,7 +216,6 @@ Binaries (with "make"):
PDF documentation (with "make pdf"):
Dynare reference manual: $BUILD_DYNARE_PDF_MANUAL
Dynare++ developer documentation: $BUILD_DYNAREPLUSPLUS_SRCDOC
Beamer presentations: $BUILD_BEAMER_DOC
Various other documents: $BUILD_OTHER_PDF_DOC
@ -278,8 +223,6 @@ HTML documentation (with "make html"):
Dynare reference manual: $BUILD_DYNARE_HTML_MANUAL
Dynare internal doc: $BUILD_DYNARE_INTERNAL_DOC
Info documentation (with "make info"): $BUILD_DYNARE_INFO
Testsuites (run with "make check"):
Dynare for Octave: $TESTSUITE_OCTAVE
Dynare++: $TESTSUITE_DYNAREPLUSPLUS

@ -1 +1 @@
Subproject commit 31b5bdc283f54733dca6352c760cd363878886e1
Subproject commit d2b2421f1d70dae079238c9a6412b5e0825ee0ef

@ -1 +1 @@
Subproject commit ce173d3fa2605957f7208bf624655893a7dc1768
Subproject commit f1d0fd61ea6d9c4f8694b373780d6c372e344f6e

View File

@ -1,15 +1,7 @@
SUBDIRS = parallel internals gsa dseries-and-reporting
info_TEXINFOS = dynare.texi
if HAVE_LATEX2HTML
html-local: dynare.html
# The temporary directory for latex2html (L2H_TMP) must not contain a dot, so
# enforce standard tmp directory instead of defaulting to current directory
dynare.html: dynare.texi
rm -rf dynare.html
texi2any --html --split=section -c L2H=1 -c L2H_TMP=$${TMPDIR:-/tmp} -c PREFIX=dynare.html dynare.texi
if HAVE_SPHINXBUILD
SUBDIRS += manual
endif
PDF_TARGETS =

File diff suppressed because it is too large Load Diff

18
doc/manual/Makefile.am Normal file
View File

@ -0,0 +1,18 @@
EXTRA_DIST = source \
utils/dynare_dom.py \
utils/dynare_lex.py
SRC = $(wildcard source/*.rst)
html-local: build/html/index.html
build/html/index.html: $(SRC) source/conf.py
$(SPHINXBUILD) -M html source build
pdf-local: build/latex/dynare-manual.pdf
build/latex/dynare-manual.pdf: $(SRC) source/conf.py
$(SPHINXBUILD) -M latexpdf source build
clean-local:
rm -rf build

View File

@ -0,0 +1,41 @@
div.sphinxsidebar {
float: left;
width: 230px;
font-size: 90%;
word-wrap: break-word;
overflow-wrap : break-word;
overflow-y: scroll;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE 10+ */
top: 0;
bottom: 0;
}
div.sphinxsidebar::-webkit-scrollbar { /* WebKit */
width: 0px;
}
div.sphinxsidebarwrapper p.logo {
padding: 0;
margin: -10px 0 0 0px;
text-align: left;
}
div.body {
min-width: 450px;
max-width: 90%;
}
.property{
display:inline-block;
text-decoration: underline;
text-decoration-style: double;
padding-right: 10px;
padding-top: 0px;
}
blockquote {
margin: 0 0 15px 30px;
padding: 0;
}

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="86.514pt" height="34.182pt" viewBox="0 0 86.514 34.182" version="1.1">
<defs>
<g>
<symbol overflow="visible" id="glyph0-0">
<path style="stroke:none;" d="M 3.09375 -14.140625 L 3.6875 -13.203125 C 3.78125 -13.015625 3.921875 -12.921875 4.140625 -12.921875 C 4.21875 -12.921875 4.328125 -12.953125 4.453125 -13.03125 C 4.5625 -13.109375 4.703125 -13.1875 4.875 -13.28125 C 5.03125 -13.375 5.234375 -13.453125 5.46875 -13.53125 C 5.6875 -13.609375 5.96875 -13.640625 6.3125 -13.640625 C 6.796875 -13.640625 7.171875 -13.515625 7.46875 -13.265625 C 7.765625 -13.015625 7.9375 -12.6875 7.9375 -12.265625 C 7.9375 -11.9375 7.859375 -11.640625 7.734375 -11.40625 C 7.59375 -11.15625 7.4375 -10.953125 7.234375 -10.765625 C 7.03125 -10.5625 6.8125 -10.390625 6.59375 -10.234375 C 6.375 -10.0625 6.15625 -9.890625 5.96875 -9.71875 C 5.78125 -9.546875 5.640625 -9.34375 5.53125 -9.125 C 5.421875 -8.921875 5.390625 -8.671875 5.421875 -8.40625 L 5.578125 -6.953125 L 7.09375 -6.953125 L 7.296875 -8.25 C 7.328125 -8.4375 7.40625 -8.609375 7.5625 -8.765625 C 7.703125 -8.90625 7.875 -9.0625 8.078125 -9.234375 C 8.28125 -9.375 8.484375 -9.546875 8.703125 -9.734375 C 8.9375 -9.90625 9.125 -10.109375 9.3125 -10.359375 C 9.5 -10.609375 9.671875 -10.890625 9.78125 -11.21875 C 9.90625 -11.546875 9.96875 -11.9375 9.96875 -12.40625 C 9.96875 -12.859375 9.890625 -13.28125 9.71875 -13.65625 C 9.546875 -14.03125 9.3125 -14.34375 9.015625 -14.625 C 8.703125 -14.875 8.34375 -15.078125 7.921875 -15.234375 C 7.5 -15.375 7.03125 -15.453125 6.5 -15.453125 C 6.125 -15.453125 5.765625 -15.40625 5.4375 -15.34375 C 5.125 -15.265625 4.8125 -15.171875 4.53125 -15.046875 C 4.25 -14.9375 3.984375 -14.796875 3.75 -14.640625 C 3.515625 -14.484375 3.296875 -14.3125 3.09375 -14.140625 Z M 4.90625 -3.625 C 4.90625 -3.21875 5.03125 -2.90625 5.296875 -2.640625 C 5.53125 -2.375 5.875 -2.25 6.265625 -2.25 C 6.4375 -2.25 6.609375 -2.28125 6.796875 -2.359375 C 6.953125 -2.421875 7.09375 -2.53125 7.21875 -2.65625 C 7.328125 -2.78125 7.421875 -2.90625 7.5 -3.078125 C 7.578125 -3.25 7.609375 -3.421875 7.609375 -3.625 C 7.609375 -3.796875 7.578125 -3.984375 7.5 -4.15625 C 7.421875 -4.328125 7.328125 -4.46875 7.21875 -4.59375 C 7.09375 -4.71875 6.953125 -4.8125 6.796875 -4.875 C 6.609375 -4.953125 6.4375 -5 6.265625 -5 C 5.875 -5 5.53125 -4.859375 5.296875 -4.59375 C 5.03125 -4.328125 4.90625 -4 4.90625 -3.625 Z M 0.5625 -17.75 L 0.5625 0 L 12.625 0 L 12.625 -17.75 Z M 1.171875 -0.671875 L 1.171875 -17.078125 L 11.921875 -17.078125 L 11.921875 -0.671875 Z M 1.171875 -0.671875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-1">
<path style="stroke:none;" d="M 17.65625 -8.875 C 17.65625 -10.203125 17.453125 -11.40625 17.03125 -12.5 C 16.609375 -13.59375 16.015625 -14.515625 15.234375 -15.296875 C 14.46875 -16.078125 13.546875 -16.6875 12.46875 -17.109375 C 11.390625 -17.53125 10.203125 -17.75 8.890625 -17.75 L 2.265625 -17.75 L 2.265625 0 L 8.890625 0 C 10.203125 0 11.390625 -0.203125 12.46875 -0.625 C 13.546875 -1.046875 14.46875 -1.65625 15.234375 -2.4375 C 16.015625 -3.203125 16.609375 -4.15625 17.03125 -5.234375 C 17.453125 -6.328125 17.65625 -7.53125 17.65625 -8.875 Z M 15.1875 -8.875 C 15.1875 -7.78125 15.046875 -6.796875 14.75 -5.953125 C 14.453125 -5.078125 14.03125 -4.359375 13.484375 -3.765625 C 12.9375 -3.171875 12.265625 -2.71875 11.5 -2.421875 C 10.71875 -2.09375 9.84375 -1.953125 8.890625 -1.953125 L 4.671875 -1.953125 L 4.671875 -15.8125 L 8.890625 -15.8125 C 9.84375 -15.8125 10.71875 -15.65625 11.5 -15.34375 C 12.265625 -15.015625 12.9375 -14.578125 13.484375 -13.984375 C 14.03125 -13.375 14.453125 -12.65625 14.75 -11.796875 C 15.046875 -10.921875 15.1875 -9.96875 15.1875 -8.875 Z M 15.1875 -8.875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-2">
<path style="stroke:none;" d="M 12.578125 -12.546875 L 10.828125 -12.546875 C 10.6875 -12.546875 10.546875 -12.5 10.421875 -12.421875 C 10.296875 -12.328125 10.21875 -12.21875 10.171875 -12.09375 L 6.90625 -4.203125 C 6.78125 -3.859375 6.65625 -3.484375 6.546875 -3.09375 C 6.4375 -3.46875 6.328125 -3.84375 6.203125 -4.1875 L 2.84375 -12.09375 C 2.796875 -12.203125 2.71875 -12.296875 2.609375 -12.40625 C 2.5 -12.5 2.359375 -12.546875 2.171875 -12.546875 L 0.265625 -12.546875 L 5.4375 -0.734375 L 3.140625 4.25 L 4.78125 4.25 C 5 4.25 5.171875 4.203125 5.296875 4.09375 C 5.40625 4 5.5 3.875 5.578125 3.703125 Z M 12.578125 -12.546875 "/>
</symbol>
<symbol overflow="visible" id="glyph0-3">
<path style="stroke:none;" d="M 3.828125 -10.734375 L 3.65625 -12.09375 C 3.578125 -12.390625 3.375 -12.546875 3.078125 -12.546875 L 1.75 -12.546875 L 1.75 0 L 3.96875 0 L 3.96875 -9.25 C 4.4375 -9.78125 4.953125 -10.203125 5.53125 -10.515625 C 6.09375 -10.828125 6.703125 -10.984375 7.359375 -10.984375 C 8.234375 -10.984375 8.890625 -10.71875 9.328125 -10.203125 C 9.765625 -9.671875 9.984375 -8.9375 9.984375 -7.984375 L 9.984375 0 L 12.203125 0 L 12.203125 -7.984375 C 12.203125 -8.703125 12.109375 -9.34375 11.9375 -9.9375 C 11.75 -10.515625 11.46875 -11.015625 11.125 -11.4375 C 10.78125 -11.859375 10.328125 -12.1875 9.8125 -12.40625 C 9.296875 -12.625 8.6875 -12.75 8 -12.75 C 7.5625 -12.75 7.140625 -12.703125 6.75 -12.59375 C 6.375 -12.5 6.015625 -12.359375 5.65625 -12.1875 C 5.3125 -12.015625 5 -11.8125 4.703125 -11.5625 C 4.390625 -11.3125 4.09375 -11.03125 3.828125 -10.734375 Z M 3.828125 -10.734375 "/>
</symbol>
<symbol overflow="visible" id="glyph0-4">
<path style="stroke:none;" d="M 8.546875 -5.65625 L 8.546875 -3.046875 C 8.296875 -2.78125 8.046875 -2.546875 7.78125 -2.34375 C 7.515625 -2.125 7.25 -1.953125 6.96875 -1.8125 C 6.671875 -1.65625 6.375 -1.53125 6.0625 -1.46875 C 5.734375 -1.390625 5.375 -1.34375 5 -1.34375 C 4.703125 -1.34375 4.421875 -1.375 4.171875 -1.453125 C 3.921875 -1.53125 3.703125 -1.640625 3.515625 -1.78125 C 3.328125 -1.9375 3.1875 -2.125 3.078125 -2.375 C 2.96875 -2.609375 2.921875 -2.90625 2.921875 -3.234375 C 2.921875 -3.578125 3.015625 -3.890625 3.21875 -4.171875 C 3.421875 -4.453125 3.75 -4.703125 4.203125 -4.90625 C 4.640625 -5.109375 5.234375 -5.28125 5.953125 -5.40625 C 6.671875 -5.53125 7.53125 -5.609375 8.546875 -5.65625 Z M 1.421875 -10.78125 L 1.828125 -10.078125 C 1.890625 -9.953125 1.984375 -9.84375 2.09375 -9.78125 C 2.1875 -9.703125 2.328125 -9.671875 2.484375 -9.671875 C 2.65625 -9.671875 2.84375 -9.734375 3.046875 -9.859375 C 3.25 -10 3.46875 -10.140625 3.734375 -10.328125 C 4.015625 -10.5 4.328125 -10.640625 4.703125 -10.78125 C 5.0625 -10.921875 5.53125 -10.984375 6.078125 -10.984375 C 6.875 -10.984375 7.5 -10.734375 7.921875 -10.234375 C 8.34375 -9.734375 8.546875 -9 8.546875 -8.03125 L 8.546875 -7.046875 C 7.109375 -7.015625 5.90625 -6.875 4.9375 -6.65625 C 3.9375 -6.4375 3.140625 -6.140625 2.546875 -5.78125 C 1.921875 -5.421875 1.484375 -5.015625 1.21875 -4.5625 C 0.9375 -4.09375 0.8125 -3.625 0.8125 -3.140625 C 0.8125 -2.5625 0.890625 -2.0625 1.078125 -1.640625 C 1.265625 -1.234375 1.515625 -0.890625 1.828125 -0.625 C 2.15625 -0.34375 2.53125 -0.140625 2.96875 0 C 3.375 0.140625 3.84375 0.203125 4.34375 0.203125 C 4.8125 0.203125 5.234375 0.15625 5.640625 0.078125 C 6.03125 -0.015625 6.40625 -0.140625 6.75 -0.296875 C 7.09375 -0.453125 7.421875 -0.65625 7.75 -0.890625 C 8.046875 -1.125 8.375 -1.40625 8.703125 -1.703125 L 8.953125 -0.515625 C 9.015625 -0.3125 9.109375 -0.171875 9.234375 -0.09375 C 9.34375 -0.03125 9.5 0 9.734375 0 L 10.703125 0 L 10.703125 -8.03125 C 10.703125 -8.71875 10.609375 -9.375 10.421875 -9.96875 C 10.21875 -10.546875 9.953125 -11.046875 9.578125 -11.46875 C 9.203125 -11.875 8.75 -12.1875 8.203125 -12.421875 C 7.65625 -12.65625 7.03125 -12.78125 6.328125 -12.78125 C 5.359375 -12.78125 4.453125 -12.59375 3.671875 -12.28125 C 2.859375 -11.9375 2.125 -11.453125 1.421875 -10.78125 Z M 1.421875 -10.78125 "/>
</symbol>
<symbol overflow="visible" id="glyph0-5">
<path style="stroke:none;" d="M 3.84375 -10.03125 L 3.6875 -11.9375 C 3.65625 -12.171875 3.59375 -12.3125 3.5 -12.421875 C 3.40625 -12.5 3.25 -12.546875 3.015625 -12.546875 L 1.75 -12.546875 L 1.75 0 L 3.96875 0 L 3.96875 -7.9375 C 4.109375 -8.34375 4.28125 -8.734375 4.484375 -9.0625 C 4.6875 -9.40625 4.890625 -9.6875 5.140625 -9.90625 C 5.390625 -10.140625 5.65625 -10.3125 5.96875 -10.4375 C 6.28125 -10.546875 6.640625 -10.609375 7.03125 -10.609375 C 7.3125 -10.609375 7.578125 -10.578125 7.796875 -10.53125 C 8.015625 -10.484375 8.171875 -10.453125 8.296875 -10.453125 C 8.5 -10.453125 8.625 -10.5625 8.671875 -10.765625 L 8.828125 -12.421875 C 8.640625 -12.546875 8.421875 -12.625 8.171875 -12.6875 C 7.9375 -12.734375 7.6875 -12.78125 7.421875 -12.78125 C 6.578125 -12.78125 5.875 -12.53125 5.296875 -12.046875 C 4.71875 -11.5625 4.234375 -10.890625 3.84375 -10.03125 Z M 3.84375 -10.03125 "/>
</symbol>
<symbol overflow="visible" id="glyph0-6">
<path style="stroke:none;" d="M 10.140625 -7.640625 L 3.28125 -7.640625 C 3.4375 -8.734375 3.796875 -9.578125 4.421875 -10.203125 C 5.046875 -10.8125 5.875 -11.125 6.9375 -11.125 C 7.4375 -11.125 7.890625 -11.046875 8.296875 -10.859375 C 8.6875 -10.6875 9.015625 -10.453125 9.296875 -10.140625 C 9.5625 -9.84375 9.78125 -9.46875 9.921875 -9.046875 C 10.078125 -8.625 10.140625 -8.15625 10.140625 -7.640625 Z M 11.9375 -1.765625 L 11.3125 -2.5625 C 11.21875 -2.703125 11.0625 -2.78125 10.890625 -2.78125 C 10.75 -2.78125 10.578125 -2.703125 10.390625 -2.578125 C 10.1875 -2.453125 9.953125 -2.3125 9.671875 -2.171875 C 9.375 -2.015625 9.015625 -1.875 8.625 -1.75 C 8.234375 -1.625 7.75 -1.5625 7.203125 -1.5625 C 6.609375 -1.5625 6.0625 -1.640625 5.59375 -1.84375 C 5.109375 -2.046875 4.703125 -2.328125 4.34375 -2.71875 C 4 -3.125 3.734375 -3.609375 3.53125 -4.203125 C 3.328125 -4.78125 3.234375 -5.484375 3.203125 -6.265625 L 11.59375 -6.265625 C 11.796875 -6.265625 11.9375 -6.3125 12.015625 -6.4375 C 12.09375 -6.546875 12.125 -6.796875 12.125 -7.140625 C 12.125 -8.03125 12 -8.828125 11.734375 -9.515625 C 11.46875 -10.203125 11.109375 -10.796875 10.625 -11.28125 C 10.15625 -11.75 9.609375 -12.125 8.96875 -12.359375 C 8.328125 -12.609375 7.625 -12.75 6.890625 -12.75 C 5.96875 -12.75 5.15625 -12.59375 4.4375 -12.265625 C 3.703125 -11.9375 3.078125 -11.515625 2.59375 -10.953125 C 2.078125 -10.390625 1.703125 -9.734375 1.421875 -8.984375 C 1.15625 -8.21875 1.03125 -7.390625 1.03125 -6.53125 C 1.03125 -5.4375 1.171875 -4.484375 1.46875 -3.65625 C 1.765625 -2.8125 2.1875 -2.125 2.71875 -1.546875 C 3.25 -0.984375 3.875 -0.5625 4.609375 -0.265625 C 5.34375 0.03125 6.140625 0.171875 7.015625 0.171875 C 7.453125 0.171875 7.921875 0.140625 8.390625 0.0625 C 8.84375 -0.015625 9.296875 -0.140625 9.734375 -0.296875 C 10.15625 -0.453125 10.5625 -0.640625 10.953125 -0.890625 C 11.328125 -1.140625 11.65625 -1.421875 11.9375 -1.765625 Z M 11.9375 -1.765625 "/>
</symbol>
</g>
<clipPath id="clip1">
<path d="M 0 6 L 21 6 L 21 34.183594 L 0 34.183594 Z M 0 6 "/>
</clipPath>
</defs>
<g id="surface1">
<g style="fill:rgb(67.059326%,70.196533%,72.941589%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="3.32" y="24.072"/>
</g>
<g style="fill:rgb(67.059326%,70.196533%,72.941589%);fill-opacity:1;">
<use xlink:href="#glyph0-2" x="22.096228" y="24.072"/>
<use xlink:href="#glyph0-3" x="34.873978" y="24.072"/>
<use xlink:href="#glyph0-4" x="48.70518" y="24.072"/>
<use xlink:href="#glyph0-5" x="61.024369" y="24.072"/>
</g>
<g style="fill:rgb(67.059326%,70.196533%,72.941589%);fill-opacity:1;">
<use xlink:href="#glyph0-6" x="69.551131" y="24.072"/>
</g>
<path style="fill:none;stroke-width:0.79701;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(49.412537%,80.784607%,99.215698%);stroke-opacity:1;stroke-miterlimit:10;" d="M -13.322906 -17.010156 C -13.322906 -17.010156 0.782563 14.802344 5.384125 15.591406 C 9.985688 16.376563 16.891938 -8.35 19.841156 -11.338281 C 22.794281 -14.326562 24.798188 -6.029687 26.645844 -5.951562 C 28.4935 -5.873437 31.434906 -10.455469 33.165375 -10.771875 C 34.895844 -11.088281 37.505219 -8.299219 39.1185 -8.221094 C 40.731781 -8.142969 43.216156 -10.127344 44.786469 -10.205469 C 46.360687 -10.283594 48.884125 -8.865625 50.458344 -8.7875 C 52.028656 -8.709375 54.552094 -9.6 56.126312 -9.639062 C 57.700531 -9.678125 60.302094 -9.111719 61.794281 -9.072656 C 63.290375 -9.033594 66.89975 -9.353906 66.89975 -9.353906 " transform="matrix(1,0,0,-1,15.194,16.775)"/>
<g style="fill:rgb(12.940979%,52.157593%,77.253723%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="3.888" y="23.505"/>
</g>
<g style="fill:rgb(12.940979%,52.157593%,77.253723%);fill-opacity:1;">
<use xlink:href="#glyph0-2" x="22.664228" y="23.505"/>
<use xlink:href="#glyph0-3" x="35.441978" y="23.505"/>
<use xlink:href="#glyph0-4" x="49.27318" y="23.505"/>
<use xlink:href="#glyph0-5" x="61.592369" y="23.505"/>
</g>
<g style="fill:rgb(12.940979%,52.157593%,77.253723%);fill-opacity:1;">
<use xlink:href="#glyph0-6" x="70.094344" y="23.505"/>
</g>
<g clip-path="url(#clip1)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.79701;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(49.412537%,80.784607%,99.215698%);stroke-opacity:1;stroke-miterlimit:10;" d="M -9.127594 -7.935937 C -9.127594 -7.935937 -5.752594 -1.135156 -5.752594 -1.135156 " transform="matrix(1,0,0,-1,15.194,16.775)"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1 @@
/usr/share/javascript/mathjax/

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View File

@ -0,0 +1,57 @@
{% if theme_logo %}
<p class="logo">
<a href="{{ pathto(master_doc) }}">
<img class="logo" src="{{ pathto('_static/' ~ theme_logo, 1) }}" alt="Logo" width=143/>
{% if theme_logo_name|lower == 'true' %}
<h1 class="logo logo-name">{{ project }}</h1>
{% endif %}
</a>
</p>
{% else %}
<h1 class="logo"><a href="{{ pathto(master_doc) }}">{{ project }}</a></h1>
{% endif %}
{% if theme_description %}
<p class="blurb">{{ theme_description }}</p>
{% endif %}
{% if theme_github_user and theme_github_repo %}
{% if theme_github_button|lower == 'true' %}
<p>
<iframe src="https://ghbtns.com/github-btn.html?user={{ theme_github_user }}&repo={{ theme_github_repo }}&type={{ theme_github_type }}&count={{ theme_github_count }}&size=large&v=2"
allowtransparency="true" frameborder="0" scrolling="0" width="200px" height="35px"></iframe>
</p>
{% endif %}
{% endif %}
{% if theme_travis_button|lower != 'false' %}
{% if theme_travis_button|lower == 'true' %}
{% set path = theme_github_user + '/' + theme_github_repo %}
{% else %}
{% set path = theme_travis_button %}
{% endif %}
<p>
<a class="badge" href="https://travis-ci.org/{{ path }}">
<img
alt="https://secure.travis-ci.org/{{ path }}.svg?branch={{ theme_badge_branch }}"
src="https://secure.travis-ci.org/{{ path }}.svg?branch={{ theme_badge_branch }}"
/>
</a>
</p>
{% endif %}
{% if theme_codecov_button|lower != 'false' %}
{% if theme_codecov_button|lower == 'true' %}
{% set path = theme_github_user + '/' + theme_github_repo %}
{% else %}
{% set path = theme_codecov_button %}
{% endif %}
<p>
<a class="badge" href="https://codecov.io/github/{{ path }}">
<img
alt="https://codecov.io/github/{{ path }}/coverage.svg?branch={{ theme_badge_branch }}"
src="https://codecov.io/github/{{ path }}/coverage.svg?branch={{ theme_badge_branch }}"
/>
</a>
</p>
{% endif %}

View File

@ -0,0 +1,11 @@
<br style="line-height:16px">
<h3>{{ _('Navigation') }}</h3>
{{ toctree(includehidden=theme_sidebar_includehidden, collapse=theme_sidebar_collapse) }}
{% if theme_extra_nav_links %}
<hr />
<ul>
{% for text, uri in theme_extra_nav_links.items() %}
<li class="toctree-l1"><a href="{{ uri }}">{{ text }}</a></li>
{% endfor %}
</ul>
{% endif %}

View File

@ -0,0 +1,73 @@
.. default-domain:: dynare
############
Bibliography
############
* Abramowitz, Milton and Irene A. Stegun (1964): “Handbook of Mathematical Functions”, Courier Dover Publications.
* Adjemian, Stéphane, Matthieu Darracq Parriès and Stéphane Moyen (2008): “Towards a monetary policy evaluation framework”, *European Central Bank Working Paper*, 942.
* Aguiar, Mark and Gopinath, Gita (2004): “Emerging Market Business Cycles: The Cycle is the Trend,” *NBER* Working Paper, 10734.
* Amisano, Gianni and Tristani, Oreste (2010): “Euro area inflation persistence in an estimated nonlinear DSGE model”, *Journal of Economic Dynamics and Control*, 34(10), 18371858.
* Andreasen, Martin M., Jesús Fernández-Villaverde, and Juan Rubio-Ramírez (2018): “The Pruned State-Space System for Non-Linear DSGE Models: Theory and Empirical Applications,” *Review of Economic Studies*, 85(1), pp. 1-49.
* Andrews, Donald W.K (1991): “Heteroskedasticity and autocorrelation consistent covariance matrix estimation”, *Econometrica*, 59(3), 817858.
* Backus, David K., Patrick J. Kehoe, and Finn E. Kydland (1992): “International Real Business Cycles,” *Journal of Political Economy*, 100(4), 745775.
* Baxter, Marianne and Robert G. King (1999): “Measuring Business Cycles: Approximate Band-pass Filters for Economic Time Series,” *Review of Economics and Statistics*, 81(4), 575593.
* Boucekkine, Raouf (1995): “An alternative methodology for solving nonlinear forward-looking models,” *Journal of Economic Dynamics and Control*, 19, 711734.
* Brooks, Stephen P., and Andrew Gelman (1998): “General methods for monitoring convergence of iterative simulations,” *Journal of Computational and Graphical Statistics*, 7, pp. 434455.
* Cardoso, Margarida F., R. L. Salcedo and S. Feyo de Azevedo (1996): “The simplex simulated annealing approach to continuous non-linear optimization,” *Computers & Chemical Engineering*, 20(9), 1065-1080.
* Chib, Siddhartha and Srikanth Ramamurthy (2010): “Tailored randomized block MCMC methods with application to DSGE models,” *Journal of Econometrics*, 155, 1938.
* Christiano, Lawrence J., Mathias Trabandt and Karl Walentin (2011): “Introducing financial frictions and unemployment into a small open economy model,” *Journal of Economic Dynamics and Control*, 35(12), 19992041.
* Christoffel, Kai, Günter Coenen and Anders Warne (2010): “Forecasting with DSGE models,” *ECB Working Paper Series*, 1185.
* Collard, Fabrice (2001): “Stochastic simulations with Dynare: A practical guide”.
* Collard, Fabrice and Michel Juillard (2001a): “Accuracy of stochastic perturbation methods: The case of asset pricing models,” *Journal of Economic Dynamics and Control*, 25, 979999.
* Collard, Fabrice and Michel Juillard (2001b): “A Higher-Order Taylor Expansion Approach to Simulation of Stochastic Forward-Looking Models with an Application to a Non-Linear Phillips Curve,” *Computational Economics*, 17, 125139.
* Corona, Angelo, M. Marchesi, Claudio Martini, and Sandro Ridella (1987): “Minimizing multimodal functions of continuous variables with the “simulated annealing” algorithm”, *ACM Transactions on Mathematical Software*, 13(3), 262280.
* Del Negro, Marco and Franck Schorfheide (2004): “Priors from General Equilibrium Models for VARs”, *International Economic Review*, 45(2), 643673.
* Dennis, Richard (2007): “Optimal Policy In Rational Expectations Models: New Solution Algorithms”, *Macroeconomic Dynamics*, 11(1), 3155.
* Durbin, J. and S. J. Koopman (2012), *Time Series Analysis by State Space Methods*, Second Revised Edition, Oxford University Press.
* Fair, Ray and John Taylor (1983): “Solution and Maximum Likelihood Estimation of Dynamic Nonlinear Rational Expectation Models,” *Econometrica*, 51, 11691185.
* Fernández-Villaverde, Jesús and Juan Rubio-Ramírez (2004): “Comparing Dynamic Equilibrium Economies to Data: A Bayesian Approach,” *Journal of Econometrics*, 123, 153187.
* Fernández-Villaverde, Jesús and Juan Rubio-Ramírez (2005): “Estimating Dynamic Equilibrium Economies: Linear versus Nonlinear Likelihood,” *Journal of Applied Econometrics*, 20, 891910.
* Fernández-Villaverde, Jesús (2010): “The econometrics of DSGE models,” *SERIEs*, 1, 349.
* Ferris, Michael C. and Todd S. Munson (1999): “Interfaces to PATH 3.0: Design, Implementation and Usage”, *Computational Optimization and Applications*, 12(1), 207227.
* Geweke, John (1992): “Evaluating the accuracy of sampling-based approaches to the calculation of posterior moments,” in J.O. Berger, J.M. Bernardo, A.P. Dawid, and A.F.M. Smith (eds.) Proceedings of the Fourth Valencia International Meeting on Bayesian Statistics, pp. 169194, Oxford University Press.
* Geweke, John (1999): “Using simulation methods for Bayesian econometric models: Inference, development and communication,” *Econometric Reviews*, 18(1), 173.
* Giordani, Paolo, Michael Pitt, and Robert Kohn (2011): “Bayesian Inference for Time Series State Space Models” in: *The Oxford Handbook of Bayesian Econometrics*, ed. by John Geweke, Gary Koop, and Herman van Dijk, Oxford University Press, 61124.
* Goffe, William L., Gary D. Ferrier, and John Rogers (1994): “Global Optimization of Statistical Functions with Simulated Annealing,” *Journal of Econometrics*, 60(1/2), 65100.
* Hansen, Nikolaus and Stefan Kern (2004): “Evaluating the CMA Evolution Strategy on Multimodal Test Functions”. In: *Eighth International Conference on Parallel Problem Solving from Nature PPSN VIII*, Proceedings, Berlin: Springer, 282291.
* Harvey, Andrew C. and Garry D.A. Phillips (1979): “Maximum likelihood estimation of regression models with autoregressive-moving average disturbances,” *Biometrika*, 66(1), 4958.
* Herbst, Edward (2015): “Using the “Chandrasekhar Recursions” for Likelihood Evaluation of DSGE Models,” *Computational Economics*, 45(4), 693705.
* Ireland, Peter (2004): “A Method for Taking Models to the Data,” *Journal of Economic Dynamics and Control*, 28, 120526.
* Iskrev, Nikolay (2010): “Local identification in DSGE models,” *Journal of Monetary Economics*, 57(2), 189202.
* Judd, Kenneth (1996): “Approximation, Perturbation, and Projection Methods in Economic Analysis”, in *Handbook of Computational Economics*, ed. by Hans Amman, David Kendrick, and John Rust, North Holland Press, 511585.
* Juillard, Michel (1996): “Dynare: A program for the resolution and simulation of dynamic models with forward variables through the use of a relaxation algorithm,” CEPREMAP, *Couverture Orange*, 9602.
* Kim, Jinill and Sunghyun Kim (2003): “Spurious welfare reversals in international business cycle models,” *Journal of International Economics*, 60, 471500.
* Kanzow, Christian and Stefania Petra (2004): “On a semismooth least squares formulation of complementarity problems with gap reduction,” *Optimization Methods and Software*, 19, 507525.
* Kim, Jinill, Sunghyun Kim, Ernst Schaumburg, and Christopher A. Sims (2008): “Calculating and using second-order accurate solutions of discrete time dynamic equilibrium models,” *Journal of Economic Dynamics and Control*, 32(11), 33973414.
* Koop, Gary (2003), *Bayesian Econometrics*, John Wiley & Sons.
* Koopman, S. J. and J. Durbin (2000): “Fast Filtering and Smoothing for Multivariate State Space Models,” *Journal of Time Series Analysis*, 21(3), 281296.
* Koopman, S. J. and J. Durbin (2003): “Filtering and Smoothing of State Vector for Diffuse State Space Models,” *Journal of Time Series Analysis*, 24(1), 8598.
* Kuntsevich, Alexei V. and Franz Kappel (1997): “SolvOpt - The solver for local nonlinear optimization problems (version 1.1, Matlab, C, FORTRAN)”, University of Graz, Graz, Austria.
* Laffargue, Jean-Pierre (1990): “Résolution dun modèle macroéconomique avec anticipations rationnelles”, *Annales dÉconomie et Statistique*, 17, 97119.
* Liu, Jane and Mike West (2001): “Combined parameter and state estimation in simulation-based filtering”, in *Sequential Monte Carlo Methods in Practice*, Eds. Doucet, Freitas and Gordon, Springer Verlag.
* Lubik, Thomas and Frank Schorfheide (2007): “Do Central Banks Respond to Exchange Rate Movements? A Structural Investigation,” *Journal of Monetary Economics*, 54(4), 10691087.
* Murray, Lawrence M., Emlyn M. Jones and John Parslow (2013): “On Disturbance State-Space Models and the Particle Marginal Metropolis-Hastings Sampler”, *SIAM/ASA Journal on Uncertainty Quantification*, 1, 494521.
* Pearlman, Joseph, David Currie, and Paul Levine (1986): “Rational expectations models with partial information,” *Economic Modelling*, 3(2), 90105.
* Planas, Christophe, Marco Ratto and Alessandro Rossi (2015): “Slice sampling in Bayesian estimation of DSGE models”.
* Pfeifer, Johannes (2013): “A Guide to Specifying Observation Equations for the Estimation of DSGE Models”.
* Pfeifer, Johannes (2014): “An Introduction to Graphs in Dynare”.
* Rabanal, Pau and Juan Rubio-Ramirez (2003): “Comparing New Keynesian Models of the Business Cycle: A Bayesian Approach,” Federal Reserve of Atlanta, *Working Paper Series*, 2003-30.
* Raftery, Adrian E. and Steven Lewis (1992): “How many iterations in the Gibbs sampler?,” in *Bayesian Statistics, Vol. 4*, ed. J.O. Berger, J.M. Bernardo, A.P. * Dawid, and A.F.M. Smith, Clarendon Press: Oxford, pp. 763-773.
* Ratto, Marco (2008): “Analysing DSGE models with global sensitivity analysis”, *Computational Economics*, 31, 115139.
* Schorfheide, Frank (2000): “Loss Function-based evaluation of DSGE models,” *Journal of Applied Econometrics*, 15(6), 645670.
* Schmitt-Grohé, Stephanie and Martin Uríbe (2004): “Solving Dynamic General Equilibrium Models Using a Second-Order Approximation to the Policy Function,” *Journal of Economic Dynamics and Control*, 28(4), 755775.
* Schnabel, Robert B. and Elizabeth Eskow (1990): “A new modified Cholesky algorithm,” *SIAM Journal of Scientific and Statistical Computing*, 11, 11361158.
* Sims, Christopher A., Daniel F. Waggoner and Tao Zha (2008): “Methods for inference in large multiple-equation Markov-switching models,” *Journal of Econometrics*, 146, 255274.
* Skoeld, Martin and Gareth O. Roberts (2003): “Density Estimation for the Metropolis-Hastings Algorithm,” *Scandinavian Journal of Statistics*, 30, 699718.
* Smets, Frank and Rafael Wouters (2003): “An Estimated Dynamic Stochastic General Equilibrium Model of the Euro Area,” *Journal of the European Economic Association*, 1(5), 11231175.
* Stock, James H. and Mark W. Watson (1999). “Forecasting Inflation,”, *Journal of Monetary Economics*, 44(2), 293335.
* Uhlig, Harald (2001): “A Toolkit for Analysing Nonlinear Dynamic Stochastic Models Easily,” in *Computational Methods for the Study of Dynamic Economies*, Eds. Ramon Marimon and Andrew Scott, Oxford University Press, 3061.
* Villemot, Sébastien (2011): “Solving rational expectations models at first order: what Dynare does,” *Dynare Working Papers*, 2, CEPREMAP.

96
doc/manual/source/conf.py Normal file
View File

@ -0,0 +1,96 @@
# -*- coding: utf-8 -*-
# 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/>.
import os
import sys
sys.path.insert(0, os.path.abspath('../utils'))
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.mathjax']
source_suffix = '.rst'
templates_path = ['_templates']
html_static_path = ['_static']
mathjax_path = 'mathjax/MathJax.js?config=TeX-AMS-MML_HTMLorMML'
master_doc = 'index'
project = u'Dynare'
copyright = u'2019, Dynare Team'
author = u'Dynare Team'
add_function_parentheses = False
# See ../utils/version.py, which is generated by autoconf
from version import version
from version import release
language = 'en'
exclude_patterns = []
highlight_language = 'dynare'
todo_include_todos = False
html_theme = 'alabaster'
html_sidebars = {
"**": [
"about.html",
"searchbox.html",
"navigation.html",
]
}
html_theme_options = {
'logo': 'dlogo.svg',
'logo_name': False,
'fixed_sidebar': True,
'page_width': '100%',
}
htmlhelp_basename = 'Dynaremanual'
latex_elements = {
'sphinxsetup': 'VerbatimBorderColor={rgb}{1,1,1},VerbatimColor={RGB}{240,240,240}, \
warningBorderColor={RGB}{255,50,50},OuterLinkColor={RGB}{34,139,34}, \
InnerLinkColor={RGB}{51,51,255},TitleColor={RGB}{51,51,255}',
'papersize': 'a4paper',
}
latex_documents = [
(master_doc, 'dynare-manual.tex', u'Dynare Reference Manual',
u'Dynare team', 'manual'),
]
man_pages = [
(master_doc, 'dynare', u'Dynare Reference Manual',
[author], 1)
]
def setup(app):
from dynare_dom import DynareDomain
from dynare_lex import DynareLexer
app.add_lexer("dynare", DynareLexer())
app.add_domain(DynareDomain)

View File

@ -0,0 +1,220 @@
.. default-domain:: dynare
.. |br| raw:: html
<br>
####################
Dynare misc commands
####################
.. command:: prior_function(OPTIONS);
|br| Executes a user-defined function on parameter draws from the prior
distribution. Dynare returns the results of the computations for
all draws in an $ndraws$ by $n$ cell array named
``oo_.prior_function_results``.
*Options*
.. option:: function = FUNCTION_NAME
The function must have the following header ``output_cell =
FILENAME(xparam1,M_,options_,oo_,estim_params_,bayestopt_,dataset_,dataset_info)``,
providing read-only access to all Dynare structures. The only
output argument allowed is a :math:`1 \times n` cell array,
which allows for storing any type of output/computations. This
option is required.
.. option:: sampling_draws = INTEGER
Number of draws used for sampling. Default: 500.
.. command:: posterior_function(OPTIONS);
|br| Same as the :comm:`prior_function` command but for the
posterior distribution. Results returned in
``oo_.posterior_function_results``.
*Options*
.. option:: function = FUNCTION_NAME
See :opt:`prior_function_function <function = FUNCTION_NAME>`.
.. option:: sampling_draws = INTEGER
See :opt:`prior_function_sampling_draws <sampling_draws = INTEGER>`.
.. command:: generate_trace_plots(CHAIN_NUMBER);
|br| Generates trace plots of the MCMC draws for all estimated
parameters and the posterior density in the specified Markov Chain
``CHAIN_NUMBER``.
.. matcomm:: internals FLAG ROUTINENAME[.m]|MODFILENAME
|br| Depending on the value of ``FLAG``, the ``internals`` command
can be used to run unitary tests specific to a Matlab/Octave
routine (if available), to display documentation about a
Matlab/Octave routine, or to extract some informations about the
state of Dynare.
*Flags*
``--test``
Performs the unitary test associated to ROUTINENAME (if this
routine exists and if the matlab/octave ``.m`` file has
unitary test sections).
*Example*
::
>> internals --test ROUTINENAME
if ``routine.m`` is not in the current directory, the full
path has to be given::
>> internals --test ../matlab/fr/ROUTINENAME
``--info``
Prints on screen the internal documentation of ROUTINENAME (if
this routine exists and if this routine has a texinfo internal
documentation header). The path to ``ROUTINENAME`` has to be
provided, if the routine is not in the current directory.
*Example*
::
>> internals --doc ../matlab/fr/ROUTINENAME
At this time, will work properly for only a small number
of routines. At the top of the (available) Matlab/Octave
routines a commented block for the internal documentation
is written in the GNU texinfo documentation format. This
block is processed by calling texinfo from
MATLAB. Consequently, texinfo has to be installed on your
machine.
``--display-mh-history``
Displays information about the previously saved MCMC draws
generated by a ``.mod`` file named MODFILENAME. This file must
be in the current directory.
*Example*
::
>> internals --display-mh-history MODFILENAME
``--load-mh-history``
|br| Loads into the Matlab/Octaves workspace informations
about the previously saved MCMC draws generated by a ``.mod``
file named MODFILENAME.
*Example*
::
>> internals --load-mh-history MODFILENAME
This will create a structure called ``mcmc_informations``
(in the workspace) with the following fields:
``Nblck``
The number of MCMC chains.
``InitialParameters``
A ``Nblck*n``, where ``n`` is the number of estimated
parameters, array of doubles. Initial state of
the MCMC.
``LastParameters``
A ``Nblck*n``, where ``n`` is the number of estimated
parameters, array of doubles. Current state of
the MCMC.
``InitialLogPost``
A ``Nblck*1`` array of doubles. Initial value of the
posterior kernel.
``LastLogPost``
A ``Nblck*1`` array of doubles. Current value of the
posterior kernel.
``InitialSeeds``
A ``1*Nblck`` structure array. Initial state of the random
number generator.
``LastSeeds``
A ``1*Nblck`` structure array. Current state of the random
number generator.
``AcceptanceRatio``
A ``1*Nblck`` array of doubles. Current acceptance ratios.
.. matcomm:: prior [options[, ...]];
Prints various informations about the prior distribution depending
on the options. If no options are provided, the command returns
the list of available options. Following options are available:
``table``
Prints a table describing the marginal prior distributions
(mean, mode, std., lower and upper bounds, HPD interval).
``moments``
Computes and displays first and second order moments of the
endogenous variables at the prior mode (considering the
linearized version of the model).
``moments(distribution)``
Computes and displays the prior mean and prior standard
deviation of the first and second moments of the endogenous
variables (considering the linearized version of the model) by
randomly sampling from the prior. The results will also be
stored in the ``prior`` subfolder in a
``_endogenous_variables_prior_draws.mat`` file.
``optimize``
Optimizes the prior density (starting from a random initial
guess). The parameters such that the steady state does not
exist or does not satisfy the Blanchard and Kahn conditions
are penalized, as they would be when maximizing the posterior
density. If a significant proportion of the prior mass is
defined over such regions, the optimization algorithm may fail
to converge to the true solution (the prior mode).
``simulate``
Computes the effective prior mass using a Monte-Carlo. Ideally
the effective prior mass should be equal to 1, otherwise
problems may arise when maximising the posterior density and
model comparison based on marginal densities may be
unfair. When comparing models, say :math:`A` and :math:`B`,
the marginal densities, :math:`m_A` and :math:`m_B`, should be
corrected for the estimated effective prior mass
:math:`p_A\neq p_B \leq 1` so that the prior mass of the
compared models are identical.
``plot``
Plots the marginal prior density.

View File

@ -0,0 +1,58 @@
.. default-domain:: dynare
########
Examples
########
Dynare comes with a database of example ``.mod`` files, which are
designed to show a broad range of Dynare features, and are taken from
academic papers for most of them. You should have these files in the
``examples`` subdirectory of your distribution.
Here is a short list of the examples included. For a more complete
description, please refer to the comments inside the files themselves.
``ramst.mod``
An elementary real business cycle (RBC) model, simulated in a
deterministic setup.
``example1.mod``
``example2.mod``
Two examples of a small RBC model in a stochastic setup, presented
in *Collard (2001)* (see the file ``guide.pdf`` which comes with
Dynare).
``example3.mod``
A small RBC model in a stochastic setup, presented in *Collard
(2001)*. The steady state is solved analytically using the
``steady_state_model`` block (see :bck:`steady_state_model`).
``fs2000.mod``
A cash in advance model, estimated by *Schorfheide (2000)*. The
file shows how to use Dynare for estimation.
``fs2000_nonstationary.mod``
The same model than ``fs2000.mod``, but written in non-stationary
form. Detrending of the equations is done by Dynare.
``bkk.mod``
Multi-country RBC model with time to build, presented in *Backus,
Kehoe and Kydland (1992)*. The file shows how to use Dynares
macro processor.
``agtrend.mod``
Small open economy RBC model with shocks to the growth trend,
presented in *Aguiar and Gopinath (2004)*.
``NK_baseline.mod``
Baseline New Keynesian Model estimated in *Fernández-Villaverde
(2010)*. It demonstrates how to use an explicit steady state file
to update parameters and call a numerical solver.

View File

@ -0,0 +1,43 @@
The Dynare Reference Manual, version 4.6-unstable.
==================================================
Currently the development team of Dynare is composed of:
* Stéphane Adjemian
* Houtan Bastani
* Michel Juillard
* Frédéric Karamé
* Junior Maih
* Ferhat Mihoubi
* Willi Mutschler
* Johannes Pfeifer
* Marco Ratto
* Sébastien Villemot
Copyright © 1996-2019, Dynare Team.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license can be found at `http://www.gnu.org/licenses/fdl.txt <http://www.gnu.org/licenses/fdl.txt>`__.
.. toctree::
:numbered:
:maxdepth: 4
introduction
installation-and-configuration
running-dynare
the-model-file
the-configuration-file
time-series
reporting
examples
dynare-misc-commands
bibliography
.. only:: builder_html
Indices and tables
==================
* :ref:`genindex`

View File

@ -0,0 +1,238 @@
.. default-domain:: dynare
##############################
Installation and configuration
##############################
Software requirements
=====================
Packaged versions of Dynare are available for Windows 7/8/10,
`Debian GNU/Linux <http://www.debian.org/>`__, `Ubuntu`_ and macOS 10.8
or later. Dynare should work on other systems, but some compilation
steps are necessary in that case.
In order to run Dynare, you need one of the following:
* MATLAB version 7.9 (R2009b) or above;
* GNU Octave version 4.2.1 or above, with the statistics package from `Octave-Forge`_.
The following optional extensions are also useful to benefit from
extra features, but are in no way required:
* If under MATLAB: the Optimization Toolbox, the Statistics Toolbox,
the Control System Toolbox;
* If under GNU Octave, the following `Octave-Forge`_ packages: ``optim, io,
control``.
Installation of Dynare
======================
After installation, Dynare can be used in any directory on your
computer. It is best practice to keep your model files in directories
different from the one containing the Dynare toolbox. That way you can
upgrade Dynare and discard the previous version without having to
worry about your own files.
On Windows
----------
Execute the automated installer called ``dynare-4.x.y-win.exe`` (where
``4.x.y`` is the version number), and follow the instructions. The
default installation directory is ``c:\dynare\4.x.y``.
After installation, this directory will contain several
sub-directories, among which are ``matlab``, ``mex`` and ``doc``.
The installer will also add an entry in your Start Menu with a
shortcut to the documentation files and uninstaller.
Note that you can have several versions of Dynare coexisting (for
example in ``c:\dynare``), as long as you correctly adjust your path
settings (see see :ref:`words-warning`).
On Debian GNU/Linux and Ubuntu
------------------------------
Please refer to the `Dynare wiki`_ for detailed instructions.
Dynare will be installed under ``/usr/lib/dynare``. Documentation will
be under ``/usr/share/doc/dynare-doc``.
On macOS
--------
To install Dynare for use with Matlab, execute the automated installer
called ``dynare-4.x.y.pkg`` (where *4.x.y* is the version number), and
follow the instructions. The default installation directory is
``/Applications/Dynare/4.x.y`` (please refer to the `Dynare wiki`_ for
detailed instructions).
After installation, this directory will contain several
sub-directories, among which are ``matlab``, ``mex`` and ``doc``.
Note that several versions of Dynare can coexist (by default in
``/Applications/Dynare``), as long as you correctly adjust your path
settings (see :ref:`words-warning`).
To install Dynare for Octave, first install Homebrew following the
instructions on their site: `https://brew.sh/
<https://brew.sh/>`__. Then install Octave, issuing the command ``brew
install octave`` at the Terminal prompt. You can then install the
latest stable version of Dynare by typing ``brew install dynare`` at
the Terminal prompt. You can also pass options to the installation
command. These options can be viewed by typing ``brew info dynare`` at
the Terminal prompt.
For other systems
-----------------
You need to download Dynare source code from the `Dynare website`_ and
unpack it somewhere.
Then you will need to recompile the pre-processor and the dynamic
loadable libraries. Please refer to `README.md
<https://git.dynare.org/Dynare/dynare/blob/master/README.md>`__.
.. _compil-install:
Compiler installation
=====================
Prerequisites on Windows
------------------------
There is no prerequisites on Windows. Dynare now ships a compilation
environment that can be used with the :opt:`use_dll` option.
Prerequisites on Debian GNU/Linux and Ubuntu
--------------------------------------------
Users of MATLAB under GNU/Linux need a working compilation
environment installed. If not already present, it can be installed via
``apt install build-essential``.
Users of Octave under GNU/Linux should install the package for MEX file
compilation (under Debian or Ubuntu, it is called ``liboctave-dev``).
Prerequisites on macOS
----------------------
[TO BE UPDATED]
If you are using MATLAB under macOS, you should install the latest
version of XCode: `see instructions on the Dynare wiki
<https://git.dynare.org/Dynare/dynare/wikis/Install-on-MacOS>`__.
Configuration
=============
For MATLAB
----------
.. highlight:: matlab
You need to add the ``matlab`` subdirectory of your Dynare
installation to MATLAB path. You have two options for doing that:
* Using the ``addpath`` command in the MATLAB command window:
Under Windows, assuming that you have installed Dynare in the
standard location, and replacing ``4.x.y`` with the correct version
number, type::
>> addpath c:/dynare/4.x.y/matlab
Under Debian GNU/Linux or Ubuntu, type::
>> addpath /usr/lib/dynare/matlab
Under macOS, assuming that you have installed Dynare in the standard
location, and replacing ``4.x.y`` with the correct version number,
type::
>> addpath /Applications/Dynare/4.x.y/matlab
MATLAB will not remember this setting next time you run it, and you
will have to do it again.
* Via the menu entries:
Select the “Set Path” entry in the “File” menu, then click on “Add
Folder…”, and select the ``matlab`` subdirectory of your Dynare
installation. Note that you *should not* use “Add with
Subfolders…”. Apply the settings by clicking on “Save”. Note that
MATLAB will remember this setting next time you run it.
For GNU Octave
--------------
You need to add the ``matlab`` subdirectory of your Dynare
installation to Octave path, using the ``addpath`` at the Octave
command prompt.
Under Windows, assuming that you have installed Dynare in the standard
location, and replacing “*4.x.y*” with the correct version number,
type::
octave:1> addpath c:/dynare/4.x.y/matlab
Under Debian GNU/Linux or Ubuntu, there is no need to use the
``addpath`` command; the packaging does it for you.
Under macOS, assuming that you have installed Dynare and Octave via
Homebrew, type::
octave:1> addpath /usr/local/opt/dynare/lib/dynare/matlab
If you dont want to type this command every time you run Octave, you
can put it in a file called ``.octaverc`` in your home directory
(under Windows this will generally be ``c:\Users\USERNAME`` while under macOS it is
``/Users/USERNAME/``). This file is run by Octave at every startup.
.. _words-warning:
Some words of warning
---------------------
You should be very careful about the content of your MATLAB or Octave
path. You can display its content by simply typing ``path`` in the
command window.
The path should normally contain system directories of MATLAB or
Octave, and some subdirectories of your Dynare installation. You have
to manually add the ``matlab`` subdirectory, and Dynare will
automatically add a few other subdirectories at runtime (depending on
your configuration). You must verify that there is no directory coming
from another version of Dynare than the one you are planning to use.
You have to be aware that adding other directories (on top of the
dynare folders) to your MATLAB or Octave path can potentially create
problems if any of your M-files have the same name as a Dynare
file. Your routine would then override the Dynare routine, making
Dynare unusable.
.. warning::
Never add all the subdirectories of the ``matlab`` folder to the
MATLAB or Octave path. You must let Dynare decide which subdirectories
have to be added to the MATLAB or Octave path. Otherwise, you may
end up with a non optimal or un-usable installation of Dynare.
.. _Ubuntu: http://www.ubuntu.com/
.. _Dynare website: https://www.dynare.org/
.. _Dynare wiki: https://git.dynare.org/Dynare/dynare/wikis
.. _Octave-Forge: http://octave.sourceforge.io/

View File

@ -0,0 +1,137 @@
.. default-domain:: dynare
############
Introduction
############
What is Dynare?
===============
Dynare is a software platform for handling a wide class of economic
models, in particular dynamic stochastic general equilibrium (DSGE)
and overlapping generations (OLG) models. The models solved by Dynare
include those relying on the *rational expectations* hypothesis,
wherein agents form their expectations about the future in a way
consistent with the model. But Dynare is also able to handle models
where expectations are formed differently: on one extreme, models
where agents perfectly anticipate the future; on the other extreme,
models where agents have limited rationality or imperfect knowledge of
the state of the economy and, hence, form their expectations through a
learning process. In terms of types of agents, models solved by Dynare
can incorporate consumers, productive firms, governments, monetary
authorities, investors and financial intermediaries. Some degree of
heterogeneity can be achieved by including several distinct classes of
agents in each of the aforementioned agent categories.
Dynare offers a user-friendly and intuitive way of describing these
models. It is able to perform simulations of the model given a
calibration of the model parameters and is also able to estimate these
parameters given a dataset. In practice, the user will write a text
file containing the list of model variables, the dynamic equations
linking these variables together, the computing tasks to be performed
and the desired graphical or numerical outputs.
A large panel of applied mathematics and computer science techniques
are internally employed by Dynare: multivariate nonlinear solving and
optimization, matrix factorizations, local functional approximation,
Kalman filters and smoothers, MCMC techniques for Bayesian estimation,
graph algorithms, optimal control, …
Various public bodies (central banks, ministries of economy and
finance, international organisations) and some private financial
institutions use Dynare for performing policy analysis exercises and
as a support tool for forecasting exercises. In the academic world,
Dynare is used for research and teaching purposes in postgraduate
macroeconomics courses.
Dynare is a free software, which means that it can be downloaded free
of charge, that its source code is freely available, and that it can
be used for both non-profit and for-profit purposes. Most of the
source files are covered by the GNU General Public Licence (GPL)
version 3 or later (there are some exceptions to this, see the file
license.txt in Dynare distribution). It is available for the Windows,
macOS, and Linux platforms and is fully documented through a reference
manual. Part of Dynare is programmed in C++, while the rest is written
using the `MATLAB`_ programming language. The latter implies that
commercially-available MATLAB software is required in order to run
Dynare. However, as an alternative to MATLAB, Dynare is also able to
run on top of `GNU Octave`_ (basically a free clone of MATLAB): this
possibility is particularly interesting for students or institutions
who cannot afford, or do not want to pay for, MATLAB and are willing
to bear the concomitant performance loss.
The development of Dynare is mainly done at `CEPREMAP`_ by a core team
of researchers who devote part of their time to software
development. Currently the development team of Dynare is composed of
Stéphane Adjemian (Université du Maine, Gains and Cepremap), Houtan
Bastani (Cepremap), Michel Juillard (Banque de France), Frédéric
Karamé (Université du Maine, Gains and Cepremap), Junior Maih (Norges
Bank), Ferhat Mihoubi (Université Paris-Est Créteil, Érudite and
Cepremap), Johannes Pfeifer (University of Cologne), Marco Ratto
(European Commission, Joint Research Centre - JRC) and Sébastien
Villemot (Cepremap). Increasingly, the developer base is expanding, as
tools developed by researchers outside of Cepremap are integrated into
Dynare. Financial support is provided by Cepremap, Banque de France
and DSGE-net (an international research network for DSGE modeling).
Interaction between developers and users of Dynare is central to the
project. A `web forum`_ is available for users who have questions
about the usage of Dynare or who want to report bugs. Current known
and fixed bugs are listed on the `Dynare wiki`_. Issues or whishes can
be reported on our `Git repository`_. Training sessions are given
through the Dynare Summer School, which is organized every year and is
attended by about 40 people. Finally, priorities in terms of future
developments and features to be added are decided in cooperation with
the institutions providing financial support.
Documentation sources
=====================
The present document is the reference manual for Dynare. It documents
all commands and features in a systematic fashion.
Other useful sources of information include the `Dynare wiki`_ and the
`Dynare forums`_.
Citing Dynare in your research
==============================
You should cite Dynare if you use it in your research. The
recommended way todo this is to cite the present manual, as:
Stéphane Adjemian, Houtan Bastani, Michel Juillard, Frédéric
Karamé, Junior Maih, Ferhat Mihoubi, George Perendia, Johannes Pfeifer, Marco
Ratto and Sébastien Villemot (2011), “Dynare: Reference Manual,
Version 4,” *Dynare Working Papers*, 1, CEPREMAP
For convenience, you can copy and paste the following into your BibTeX file:
.. code-block:: bibtex
@TechReport{Adjemianetal2011,
author = {Adjemian, St\'ephane and Bastani, Houtan and Juillard, Michel and
Karam\'e, Fr\'ederic and Maih, Junior and Mihoubi, Ferhat and
Perendia, George and Pfeifer, Johannes and Ratto, Marco and
Villemot, S\'ebastien},
title = {Dynare: Reference Manual Version 4},
year = {2011},
institution = {CEPREMAP},
type = {Dynare Working Papers},
number = {1},
}
If you want to give a URL, use the address of the Dynare website:
https://www.dynare.org.
.. _MATLAB: http://www.mathworks.com/products/matlab/
.. _GNU Octave: http://www.octave.org/
.. _CEPREMAP: http://www.cepremap.fr/
.. _web forum: https://forum.dynare.org/
.. _official Dynare website: http://www.dynare.org/
.. _Dynare wiki: https://git.dynare.org/Dynare/dynare/wikis
.. _Dynare forums: https://forum.dynare.org/
.. _Git repository: https://git.dynare.org/Dynare/dynare

View File

@ -0,0 +1,884 @@
.. default-domain:: dynare
.. |br| raw:: html
<br>
.. highlight:: matlab
#########
Reporting
#########
Dynare provides a simple interface for creating :math:`\text{\LaTeX}`
reports, comprised of :math:`\text{\LaTeX}` tables and ``PGFPLOTS/TikZ
graphs``. You can use the report as created through Dynare or pick out
the pieces (tables and graphs) you want for inclusion in your own
paper. Though Dynare provides a subset of options available through
``PGFPLOTS/TikZ``, you can easily modify the graphs created by Dynare
using the options available in the ``PGFPLOTS/TikZ`` manual. You can
either do this manually or by passing the options to
:opt:`miscTikzAxisOptions <miscTikzAxisOptions, STRING>` or
:opt:`graphMiscTikzAddPlotOptions <graphMiscTikzAddPlotOptions,
STRING>`.
Reports are created and modified by calling methods on class
objects. The objects are hierarchical, with the following order (from
highest to lowest): ``Report``, ``Page``, ``Section``,
``Graph/Table/Vspace``, ``Series``. For simplicity of syntax, we
abstract away from these classes, allowing you to operate directly on
a ``Report`` object, while maintaining the names of these classes in
the ``Report`` class methods you will use.
The report is created sequentially, command by command, hence the
order of the commands matters. When an object of a certain hierarchy
is inserted, all methods will function on that object until an object
of equal or greater hierarchy is added. Hence, once you add a ``Page``
to the report, every time you add a ``Section`` object, it will be
added to this ``Page`` until another ``Page`` is added to the report
(via :repmeth:`addPage`). This will become more clear with the example
at the end of the section.
Options to methods are passed differently than those to Dynare
commands. They take the form of named options to Matlab functions
where the arguments come in pairs
(e.g. ``function_name(`option_1_name', `option_1_value',
`option_2_name', `option_2_value', ...)``, where ``option_X_name`` is
the name of the option while ``option_X_value`` is the value assigned
to that option). The ordering of the option pairs matters only in the
unusual case when an option is provided twice (probably
erroneously). In this case, the last value passed is the one that is
used.
Below, you will see a list of methods available for the Report class
and a clarifying example.
.. construct:: report
|br| Instantiates a ``Report`` object.
*Options*
.. option:: compiler, FILENAME
The full path to the :math:`\text{\LaTeX}` compiler on your
system. If this option is not provided, Dynare will try to
find the appropriate program to compile :math:`\text{\LaTeX}` on your
system. Default is system dependent:
* Windows: the result of findtexmf ``--file-type=exe pdflatex``.
* macOS and Linux: the result of ``which pdflatex``.
.. option:: directory, FILENAME
The path to the directory you want the report created in. Default:
current directory.
.. option:: showDate, BOOLEAN
Display the date and time when the report was
compiled. Default: ``true``.
.. option:: fileName, FILENAME
The file name to use when saving this report. Default: ``report.tex``.
.. option:: header, STRING
The valid :math:`\text{\LaTeX}` code to be included in the report before
``\begin{document}``. Default: ``empty``.
.. option:: margin, DOUBLE
The margin size. Default: ``2.5``.
.. option:: marginUnit, `cm' | `in'
Units associated with the margin. Default: ```cm'``.
.. option:: orientation, `landscape' | `portrait'
Paper orientation: Default: ```portrait'``.
.. option:: paper, `a4' | `letter'
Paper size. Default: ```a4'``.
.. option:: showOutput, BOOLEAN
Print report creation progress to screen. Shows you the page
number as it is created and as it is written. This is useful
to see where a potential error occurs in report
creation. Default: ``true``.
.. option:: title, STRING
Report Title. Default: ``none``.
.. reportingmethod:: addPage
|br| Adds a Page to the Report.
*Options*
.. option:: footnote, STRING
A footnote to be included at the bottom of this page. Default: ``none``.
.. option:: latex, STRING
The valid :math:`\text{\LaTeX}` code to be used for this
page. Alows the user to create a page to be included in the
report by passing :math:`\text{\LaTeX}` code directly. If this option is
passed, the page itself will be saved in the :opt:`pageDirName
<pageDirName, FILENAME>` directory in the form ``page_X.tex``
where X refers to the page number. Default: ``empty``.
.. option:: orientation, `landscape' | `portrait'
See :opt:`orientation <orientation, `landscape' | `portrait'>`.
.. option:: pageDirName, FILENAME
The name of the folder in which to store this page. Directory given is
relative to the `directory` option of the report class. Only used when
the :opt:`latex <latex, STRING>` command is passed. Default:
``tmpRepDir``.
.. option:: paper, `a4' | `letter'
See :opt:`paper <paper, `a4' | `letter'>`.
.. option:: title, STRING | CELL_ARRAY_STRINGS
With one entry (a STRING), the title of the page. With more
than one entry (a CELL_ARRAY_STRINGS), the title and
subtitle(s) of the page. Values passed must be valid
:math:`\text{\LaTeX}` code (e.g., ``%`` must be
``\%``). Default: ``none``.
.. option:: titleFormat, STRING | CELL_ARRAY_STRINGS
A string representing the valid :math:`\text{\LaTeX}` markup to use on
``title``. The number of cell array entries must be equal to
that of the ``title`` option if you do not want to use the
default value for the title (and subtitles). Default:
``\large\bfseries``.
.. option:: titleTruncate, INTEGER
Useful when automatically generating page titles that may
become too long, ``titleTruncate`` can be used to truncate a
title (and subsequent subtitles) when they pass the specified
number of characters. Default: ``.off``.
.. reportingmethod:: addSection
|br| Adds a ``Section`` to a ``Page``.
*Options*
.. option:: cols, INTEGER
The number of columns in the section. Default: ``1``.
.. option:: height, STRING
A string to be used with the ``\sectionheight`` :math:`\text{\LaTeX}`
command. Default: ``'!'``
.. reportingmethod:: addGraph
|br| Adds a ``Graph`` to a ``Section``.
*Options*
.. option:: data, dseries
The ``dseries`` that provides the data for the graph. Default: ``none``.
.. option:: axisShape, `box' | `L'
The shape the axis should have. ```box'`` means that there is
an axis line to the left, right, bottom, and top of the
graphed line(s). 'L'`` means that there is an axis to the left
and bottom of the graphed line(s). Default: ```box'``.
.. option:: graphDirName, FILENAME
The name of the folder in which to store this figure. Directory given
is relative to the `directory` option of the report class. Default:
``tmpRepDir``.
.. option:: graphName, STRING
The name to use when saving this figure. Default: something of
the form ``graph_pg1_sec2_row1_col3.tex``.
.. option:: height, DOUBLE
The height of the graph, in inches. Default: ``4.5``.
.. option:: showGrid, BOOLEAN
Whether or not to display the major grid on the
graph. Default: ``true``.
.. option:: showLegend, BOOLEAN
Whether or not to display the legend.
Unless you use the :opt:`graphLegendName <graphLegendName,
STRING>` option, the name displayed in the legend is the tex
name associated with the ``dseries``. You can modify this tex
name by using :dsermeth:`tex_rename <B =
tex_rename>`. Default: ``false``.
.. option:: legendAt, NUMERICAL_VECTOR
The coordinates for the legend location. If this option is
passed, it overrides the :opt:`legendLocation <legendLocation,
OPTION>` option. Must be of size ``2``. Default: ``empty``.
.. option:: showLegendBox, BOOLEAN
Whether or not to display a box around the legend. Default: ``false``.
.. option:: legendLocation, OPTION
Where to place the legend in the graph. Possible values for OPTION are::
`south west' | `south east' | `north west' | `north east' | `outer north east'
Default: ```south east'``.
.. option:: legendOrientation, `vertical' | `horizontal'
Orientation of the legend. Default: ```horizontal'``.
.. option:: legendFontSize, OPTION
The font size for legend entries. Possible values for OPTION are::
`tiny' | `scriptsize' | `footnotesize' | `small' | `normalsize' |
`large' | `Large' | `LARGE' | `huge' | `Huge'
Default: ``tiny``.
.. option:: miscTikzAxisOptions, STRING
If you are comfortable with ``PGFPLOTS/TikZ``, you can use
this option to pass arguments directly to the
``PGFPLOTS/TikZ`` axis environment command. Specifically to be
used for desired ``PGFPLOTS/TikZ`` options that have not been
incorporated into Dynare Reporting. Default: ``empty``.
.. option:: miscTikzPictureOptions, STRING
If you are comfortable with ``PGFPLOTS/TikZ``, you can use
this option to pass arguments directly to the
``PGFPLOTS/TikZ`` ``tikzpicture`` environment command. (e.g.,
to scale the graph in the x and y dimensions, you can pass
following to this option: 'xscale=2.5,
yscale=0.5'``). Specifically to be used for desired
``PGFPLOTS/TikZ`` options that have not been incorporated into
Dynare Reporting. Default: ``empty``.
.. option:: seriesToUse, CELL_ARRAY_STRINGS
The names of the series contained in the ``dseries`` provided
to the :opt:`data <data, dseries>` option. If empty, use all
series provided to ``data`` option. Default: ``empty``.
.. option:: shade, dates
The date range showing the portion of the graph that should be
shaded. Default: ``none``.
.. option:: shadeColor, STRING
The color to use in the shaded portion of the graph. All valid
color strings defined for use by ``PGFPLOTS/TikZ`` are
valid. A list of defined colors is::
'red', 'green', 'blue', 'cyan', 'magenta', 'yellow', 'black', 'gray',
'white','darkgray', 'lightgray', 'brown', 'lime', 'olive', 'orange',
'pink', 'purple', 'teal', 'violet'.
Furthermore, You can use combinations of these colors. For
example, if you wanted a color that is 20\% green and 80\%
purple, you could pass the string ``'green!20!purple'``. You
can also use RGB colors, following the syntax:
```rgb,255:red,231;green,84;blue,121'`` which corresponds to
the RGB color ``(231;84;121)``. More examples are available in
the section 4.7.5 of the ``PGFPLOTS/TikZ`` manual, revision
1.10. Default: ```green'``
.. option:: shadeOpacity, DOUBLE
The opacity of the shaded area, must be in ``[0,100]``. Default: ``20``.
.. option:: tickFontSize, OPTION
The font size for x- and y-axis tick labels. Possible values
for OPTION are::
`tiny' | `scriptsize' | `footnotesize' | `small' | `normalsize' |
`large' | `Large' | `LARGE' | `huge' | `Huge'
Default: ``normalsize``.
.. option:: title, STRING | CELL_ARRAY_STRINGS
Same as :opt:`title <title, STRING | CELL_ARRAY_STRINGS>`,
just for graphs.
.. option:: titleFontSize, OPTION
The font size for title. Possible values for OPTION are::
`tiny' | `scriptsize' | `footnotesize' | `small' | `normalsize' |
`large' | `Large' | `LARGE' | `huge' | `Huge'
Default: ``normalsize``.
.. option:: titleFormat, STRING
The format to use for the graph title. Unlike
:opt:`titleFormat <titleFormat, STRING | CELL_ARRAY_STRINGS>`,
due to a constraint of ``TikZ``, this format applies to the
title and subtitles. Default: ``TikZ`` default.
.. option:: width, DOUBLE
The width of the graph, in inches. Default: ``6.0``.
.. option:: writeCSV, BOOLEAN
Whether or not to write a CSV file with only the plotted
data. The file will be saved in the directory specified by
:opt:`graphDirName <graphDirName, FILENAME>` with the same base
name as specified by :opt:`graphName <graphName, STRING>` with
the ending ``.csv``. Default: ``false``.
.. option:: xlabel, STRING
The x-axis label. Default: ``none``.
.. option:: ylabel, STRING
The y-axis label. Default: ``none``.
.. option:: xAxisTight, BOOLEAN
Use a tight x axis. If false, uses ``PGFPLOTS/TikZ`` ``enlarge
x limits`` to choose appropriate axis size. Default: ``true``.
.. option:: xrange, dates
The boundary on the x-axis to display in the graph. Default: ``all``.
.. option:: xTicks, NUMERICAL_VECTOR
Used only in conjunction with :opt:`xTickLabels <xTickLabels,
CELL_ARRAY_STRINGS | `ALL'>`, this option denotes the
numerical position of the label along the x-axis. The
positions begin at ``1``. Default: the indices associated with
the first and last dates of the ``dseries`` and, if passed,
the index associated with the first date of the :opt:`shade
<shade, dates>` option.
.. option:: xTickLabels, CELL_ARRAY_STRINGS | `ALL'
The labels to be mapped to the ticks provided by
``xTicks``. Default: the first and last dates of the
``dseries`` and, if passed, the date first date of the
:opt:`shade <shade, dates>` option.
.. option:: xTickLabelAnchor, STRING
Where to anchor the x tick label. Default: ```east'``.
.. option:: xTickLabelRotation, DOUBLE
The amount to rotate the x tick labels by. Default: ``0``.
.. option:: yAxisTight, BOOLEAN
Use a tight y axis. If false, uses ``PGFPLOTS/TikZ`` ``enlarge
y limits`` to choose appropriate axis size. Default:
``false``.
.. option:: yrange, NUMERICAL_VECTOR
The boundary on the y-axis to display in the graph,
represented as a ``NUMERICAL_VECTOR`` of size ``2``, with the
first entry less than the second entry. Default: ``all``.
.. option:: yTickLabelFixed, BOOLEAN
Round the y tick labels to a fixed number of decimal places,
given by ``yTickLabelPrecision``. Default: ``true``.
.. option:: yTickLabelPrecision, INTEGER
The precision with which to report the ``yTickLabel``. Default: ``0``.
.. option:: yTickLabelScaled, BOOLEAN
Determines whether or not there is a common scaling factor for
the y axis. Default: ``true``.
.. option:: yTickLabelZeroFill, BOOLEAN
Whether or not to fill missing precision spots with
zeros. Default: ``true``.
.. option:: showZeroline, BOOLEAN
Display a solid black line at :math:`y = 0`. Default: ``false``.
.. option:: zeroLineColor, STRING
The color to use for the zero line. Only used if
:opt:`showZeroLine <showZeroline, BOOLEAN>` is true. See the
explanation in :opt:`shadeColor <shadeColor, STRING>` for how
to use colors with reports. Default: ```black'``.
.. reportingmethod:: addTable
|br| Adds a ``Table`` to a ``Section``.
*Options*
.. option:: data, dseries
See :opt:`data <data, dseries>`.
.. option:: highlightRows, CELL_ARRAY_STRINGS
A cell array containing the colors to use for row
highlighting. See :opt:`shadeColor <shadeColor, STRING>` for
how to use colors with reports. Highlighting for a specific
row can be overridden by using the :opt:`tableRowColor
<tableRowColor, STRING>` option to
:repmeth:`addSeries`. Default: ``empty``.
.. option:: showHlines, BOOLEAN
Whether or not to show horizontal lines separating the
rows. Default: ``false``.
.. option:: precision, INTEGER
The number of decimal places to report in the table data
(rounding done via the *round half away from zero*
method). Default: ``1``.
.. option:: range, dates
The date range of the data to be displayed. Default: ``all``.
.. option:: seriesToUse, CELL_ARRAY_STRINGS
See :opt:`seriesToUse <seriesToUse, CELL_ARRAY_STRINGS>`.
.. option:: tableDirName, FILENAME
The name of the folder in which to store this table. Directory given is
relative to the `directory` option of the report class. Default:
``tmpRepDir``.
.. option:: tableName, STRING
The name to use when saving this table. Default: something of
the form ``table_pg1_sec2_row1_col3.tex``.
.. option:: title, STRING
Same as :opt:`title <title, STRING>`, just for tables.
.. option:: titleFormat, STRING
Same as :opt:`titleFormat <titleFormat, STRING | CELL_ARRAY_STRINGS>`,
just for tables. Default: ``\large``.
.. option:: vlineAfter, dates | CELL_ARRAY_DATES
Show a vertical line after the specified date (or dates if a
cell array of dates is passed). Default: ``empty``.
.. option:: vlineAfterEndOfPeriod, BOOLEAN
Show a vertical line after the end of every period (i.e. after
every year, after the fourth quarter, etc.). Default:
``false``.
.. option:: showVlines, BOOLEAN
Whether or not to show vertical lines separating the
columns. Default: ``false``.
.. option:: writeCSV, BOOLEAN
Whether or not to write a CSV file containing the data
displayed in the table. The file will be saved in the
directory specified by :opt:`tableDirName <tableDirName,
FILENAME>` with the same base name as specified by
:opt:`tableName <tableName, STRING>` with the ending
``.csv``. Default: ``false``.
.. reportingmethod:: addSeries
|br| Adds a ``Series`` to a ``Graph`` or a ``Table``.
Options specific to graphs begin with ```graph'`` while options
specific to tables begin with ```table'``.
*Options*
.. option:: data, dseries
See :opt:`data <data, dseries>`.
.. option:: graphBar, BOOLEAN
Whether or not to display this series as a bar graph as oppsed
to the default of displaying it as a line graph. Default:
``false``.
.. option:: graphFanShadeColor, STRING
The shading color to use between a series and the
previously-added series in a graph. Useful for making fan
charts. Default: ``empty``.
.. option:: graphFanShadeOpacity, INTEGER
The opacity of the color passed in :opt:`graphFanShadeColor
<graphFanShadeColor, STRING>`. Default: ``50``.
.. option:: graphBarColor, STRING
The outline color of each bar in the bar graph. Only active if
:opt:`graphBar <graphBar, BOOLEAN>` is passed. Default:
```black'``.
.. option:: graphBarFillColor, STRING
The fill color of each bar in the bar graph. Only active if
:opt:`graphBar <graphBar, BOOLEAN>` is passed. Default:
```black'``.
.. option:: graphBarWidth, DOUBLE
The width of each bar in the bar graph. Only active if
:opt:`graphBar <graphBar, BOOLEAN>` is passed. Default: ``2``.
.. option:: graphHline, DOUBLE
Use this option to draw a horizontal line at the given
value. Default: ``empty``.
.. option:: graphLegendName, STRING
The name to display in the legend for this series, passed as
valid :math:`\text{\LaTeX}` (e.g., ``GDP_{US}, $\alpha$,
\color{red}GDP\color{black}``). Will be displayed only if the
``data`` and :opt:`showLegend <showLegend, BOOLEAN>` options
have been passed. Default: the tex name of the series.
.. option:: graphLineColor, STRING
Color to use for the series in a graph. See the explanation in
:opt:`shadeColor <shadeColor, STRING>` for how to use colors
with reports. Default: ```black'``
.. option:: graphLineStyle, OPTION
Line style for this series in a graph. Possible values for OPTION are::
`none' | `solid' | `dotted' | `densely dotted' | `loosely dotted' | `dashed' |
`densely dashed' | `loosely dashed' | `dashdotted' | `densely dashdotted' |
`loosely dashdotted' | `dashdotdotted' | `densely dashdotdotted' |
`loosely dashdotdotted'
Default: ```solid'``.
.. option:: graphLineWidth DOUBLE
Line width for this series in a graph. Default: ``0.5``.
.. option:: graphMarker, OPTION
The Marker to use on this series in a graph. Possible values
for OPTION are::
`x' | `+' | `-' | `|' | `o' | `asterisk' | `star' | `10-pointed star' |
`oplus' | `oplus*' | `otimes' | `otimes*' | `square' | `square*' |
`triangle' | `triangle*' | `diamond' | `diamond*' | `halfdiamond*' |
`halfsquare*' | `halfsquare right*' | `halfsquare left*' | `Mercedes star' |
`Mercedes star flipped' | `halfcircle' | `halfcircle*' | `pentagon' |
`pentagon star'
Default: ``none``.
.. option:: graphMarkerEdgeColor, STRING
The edge color of the graph marker. See the explanation in
:opt:`shadeColor <shadeColor, STRING>` for how to use colors
with reports. Default: ``graphLineColor``.
.. option:: graphMarkerFaceColor, STRING
The face color of the graph marker. See the explanation in
:opt:`shadeColor <shadeColor, STRING>` for how to use colors
with reports. Default: ``graphLineColor``.
.. option:: graphMarkerSize, DOUBLE
The size of the graph marker. Default: ``1``.
.. option:: graphMiscTikzAddPlotOptions, STRING
If you are comfortable with ``PGFPLOTS/TikZ``, you can use
this option to pass arguments directly to the
``PGFPLOTS/TikZ`` ``addPlots`` command. (e.g., Instead of
passing the marker options above, you can pass a string such
as the following to this option: ```mark=halfcircle*,mark
options={rotate=90,scale=3}'``). Specifically to be used for
desired ``PGFPLOTS/TikZ`` options that have not been
incorporated into Dynare Reproting. Default: ``empty``.
.. option:: graphShowInLegend, BOOLEAN
Whether or not to show this series in the legend, given that
the :opt:`showLegend <showLegend, BOOLEAN>` option was passed
to :repmeth:`addGraph`. Default: ``true``.
.. option:: graphVline, dates
Use this option to draw a vertical line at a given
date. Default: ``empty``.
.. option:: tableDataRhs, dseries
A series to be added to the right of the current
series. Usefull for displaying aggregate data for a
series. e.g if the series is quarterly ``tableDataRhs`` could
point to the yearly averages of the quarterly series. This
would cause quarterly data to be displayed followed by annual
data. Default: ``empty``.
.. option:: tableRowColor, STRING
The color that you want the row to be. Predefined values
include ``LightCyan`` and ``Gray``. Default: ``white``.
.. option:: tableRowIndent, INTEGER
The number of times to indent the name of the series in the
table. Used to create subgroups of series. Default: ``0``.
.. option:: tableShowMarkers, BOOLEAN
In a Table, if ``true``, surround each cell with brackets and
color it according to :opt:`tableNegColor <tableNegColor,
LATEX_COLOR>` and :opt:`tablePosColor <tablePosColor,
LATEX_COLOR>`. No effect for graphs. Default: ``false``.
.. option:: tableAlignRight, BOOLEAN
Whether or not to align the series name to the right of the
cell. Default: ``false``.
.. option:: tableMarkerLimit, DOUBLE
For values less than :math:`-1*\texttt{tableMarkerLimit}`,
mark the cell with the color denoted by tableNegColor. For
those greater than ``tableMarkerLimit``, mark the cell with
the color denoted by tablePosColor. Default: ``1e-4``.
.. option:: tableNaNSymb, STRING
Replace ``NaN`` values with the text in this option. Default: ``NaN``.
.. option:: tableNegColor, LATEX_COLOR
The color to use when marking Table data that is less than
zero. Default: ```red'``
.. option:: tablePrecision, INTEGER
The number of decimal places to report in the table
data. Default: the value set by :opt:`precision <precision,
INTEGER>`.
.. option:: tablePosColor, LATEX_COLOR
The color to use when marking Table data that is greater than
zero. Default: ```blue'``
.. option:: tableSubSectionHeader, STRING
A header for a subsection of the table. No data will be
associated with it. It is equivalent to adding an empty series
with a name. Default: ``''``
.. option:: zeroTol, DOUBLE
The zero tolerance. Anything smaller than ``zeroTol`` and
larger than ``-zeroTol`` will be set to zero before being
graphed or written to the table. Default: ``1e-6``.
.. reportingmethod:: addParagraph
|br| Adds a ``Paragraph`` to a ``Section``.
The ``Section`` can only be comprised of ``Paragraphs`` and must
only have 1 column.
*Options*
.. option:: balancedCols, BOOLEAN
Determines whether the text is spread out evenly across the
columns when the ``Paragraph`` has more than one
column. Default: ``true``.
.. option:: cols, INTEGER
The number of columns for the ``Paragraph``. Default: ``1``.
.. option:: heading, STRING
The heading for the ``Paragraph`` (like a section
heading). The string must be valid :math:`\text{\LaTeX}` code. Default:
``empty``.
.. option:: indent, BOOLEAN
Whether or not to indent the paragraph. Default: ``true``.
.. option:: text, STRING
The paragraph itself. The string must be valid :math:`\text{\LaTeX}`
code. Default: ``empty``.
.. reportingmethod:: addVspace
|br| Adds a ``Vspace`` (vertical space) to a ``Section``.
*Options*
.. option:: hline, INTEGER
The number of horizontal lines to be inserted. Default: ``0``.
.. option:: number, INTEGER
The number of new lines to be inserted. Default: ``1``.
.. reportingmethod:: write
|br| Writes the :math:`\text{\LaTeX}` representation of this
``Report``, saving it to the file specified by :opt:`filename
<fileName, FILENAME>`.
.. reportingmethod:: compile
|br| Compiles the report written by ``write`` into a ``pdf``
file. If the report has not already been written (determined by
the existence of the file specified by :opt:`filename <fileName,
FILENAME>`, ``write`` is called.
*Options*
.. option:: compiler, FILENAME
Like :opt:`compiler <compiler, FILENAME>`, except will not
overwrite the value of ``compiler`` contained in the report
object. Hence, passing the value here is useful for using
different :math:`\text{\LaTeX}` compilers or just for passing
the value at the last minute.
.. option:: showOutput, BOOLEAN
Print the compiler output to the screen. Useful for debugging
your code as the :math:`\text{\LaTeX}` compiler hangs if there is a
problem. Default: the value of :opt:`showOutput <showOutput,
BOOLEAN>`.
.. option:: showReport, BOOLEAN
Open the compiled report (works on Windows and macOS on
Matlab). Default: ``true``.
*Example*
The following code creates a one page report. The first part of the
page contains two graphs displayed across two columns and one row. The
bottom of the page displays a centered table::
%% Create dseries
dsq = dseries(`quarterly.csv');
dsa = dseries(`annual.csv');
dsca = dseries(`annual_control.csv');
%% Report
rep = report();
%% Page 1
rep.addPage('title', {'My Page Title', 'My Page Subtitle'}, ...
'titleFormat', {'\large\bfseries', '\large'});
% Section 1
rep.addSection('cols', 2);
rep.addGraph('title', 'Graph Column 1', 'showLegend', true, ...
'xrange', dates('2007q1'):dates('2013q4'), ...
'shade', dates('2012q2'):dates('2013q4'));
rep.addSeries('data', dsq{'GROWTH_US'}, 'graphLineColor', 'blue', ...
'graphLineStyle', 'loosely dashed', 'graphLineWidth', 1);
rep.addSeries('data', dsq{'GROWTH_EU'}, 'graphLineColor', 'green', ...
'graphLineWidth', 1.5);
rep.addGraph('title', 'Graph Column 2', 'showLegend', true, ...
'xrange', dates('2007q1'):dates('2013q4'), ...
'shade', dates('2012q2'):dates('2013q4'));
rep.addSeries('data', dsq{'GROWTH_JA'}, 'graphLineColor', 'blue', ...
'graphLineWidth', 1);
rep.addSeries('data', dsq{'GROWTH_RC6'}, 'graphLineColor', 'green', ...
'graphLineStyle', 'dashdotdotted', 'graphLineWidth', 1.5);
% Section 2
rep.addVspace('number', 15);
rep.addSection();
rep.addTable('title', 'Table 1', 'range', dates('2012Y'):dates('2014Y'));
shortNames = {'US', 'EU'};
longNames = {'United States', 'Euro Area'};
for i=1:length(shortNames)
rep.addSeries('data', dsa{['GROWTH_' shortNames{i}]});
delta = dsa{['GROWTH_' shortNames{i}]}-dsca{['GROWTH_' shortNames{i}]};
delta.tex_rename_('$\Delta$');
rep.addSeries('data', delta, ...
'tableShowMarkers', true, 'tableAlignRight', true);
end
%% Write & Compile Report
rep.write();
rep.compile();
Once compiled, the report looks like:
.. image:: _static/report.png

View File

@ -0,0 +1,511 @@
.. default-domain:: dynare
##############
Running Dynare
##############
In order to give instructions to Dynare, the user has to write a
*model file* whose filename extension must be ``.mod`` or
``.dyn``. This file contains the description of the model and the
computing tasks required by the user. Its contents are described in
:ref:`model-file`.
.. _dyn-invoc:
Dynare invocation
=================
Once the model file is written, Dynare is invoked using the ``dynare``
command at the MATLAB or Octave prompt (with the filename of the
``.mod`` given as argument).
In practice, the handling of the model file is done in two steps: in
the first one, the model and the processing instructions written by
the user in a *model file* are interpreted and the proper MATLAB or
GNU Octave instructions are generated; in the second step, the program
actually runs the computations. Both steps are triggered automatically
by the ``dynare`` command.
.. matcomm:: dynare FILENAME[.mod] [OPTIONS…]
This command launches Dynare and executes the instructions
included in ``FILENAME.mod``. This user-supplied file contains the
model and the processing instructions, as described in
:ref:`model-file`. The options, listed below, can be passed on the
command line, following the name of the ``.mod`` file or in the
first line of the ``.mod`` file itself (see below).
dynare begins by launching the preprocessor on the ``.mod
file``. By default (unless ``use_dll`` option has been given to
``model``), the preprocessor creates three intermediary files:
- ``+FILENAME/driver.m``
Contains variable declarations, and computing tasks.
- ``+FILENAME/dynamic.m``
Contains the dynamic model equations. Note that Dynare might
introduce auxiliary equations and variables (see
:ref:`aux-variables`). Outputs are the residuals of the
dynamic model equations in the order the equations were
declared and the Jacobian of the dynamic model equations. For
higher order approximations also the Hessian and the
third-order derivatives are provided. When computing the
Jacobian of the dynamic model, the order of the endogenous
variables in the columns is stored in
``M_.lead_lag_incidence``. The rows of this matrix represent
time periods: the first row denotes a lagged (time t-1)
variable, the second row a contemporaneous (time t) variable,
and the third row a leaded (time t+1) variable. The columns of
the matrix represent the endogenous variables in their order
of declaration. A zero in the matrix means that this
endogenous does not appear in the model in this time
period. The value in the ``M_.lead_lag_incidence`` matrix
corresponds to the column of that variable in the Jacobian of
the dynamic model. Example: Let the second declared variable
be ``c`` and the ``(3,2)`` entry of ``M_.lead_lag_incidence``
be 15. Then the 15th column of the Jacobian is the derivative
with respect to ``c(+1)``.
- ``+FILENAME/static.m``
Contains the long run static model equations. Note that Dynare
might introduce auxiliary equations and variables (see
:ref:`aux-variables`). Outputs are the residuals of the static
model equations in the order the equations were declared and
the Jacobian of the static equations. Entry ``(i,j)`` of the
Jacobian represents the derivative of the ith static model
equation with respect to the jth model variable in declaration
order.
These files may be looked at to understand errors reported at the
simulation stage.
``dynare`` will then run the computing tasks by executing
``+FILENAME/driver.m``. If a user needs to rerun the computing
tasks without calling the preprocessor (or without calling the
:mcomm:`dynare` command), for
instance because he has modified the script, he just have to type
the following on the command line:
.. code-block:: matlab
>> FILENAME.driver
A few words of warning are warranted here: under Octave the
filename of the ``.mod`` file should be chosen in such a way that
the generated ``.m`` files described above do not conflict with
``.m`` files provided by Octave or by Dynare. Not
respecting this rule could cause crashes or unexpected
behaviour. In particular, it means that the ``.mod`` file cannot
be given the name of an Octave or Dynare command. For instance, under
Octave, it also means that the ``.mod`` file cannot be named
``test.mod`` or ``example.mod``.
*Options*
.. option:: noclearall
By default, ``dynare`` will issue a ``clear all`` command to
MATLAB (<R2015b) or Octave, thereby deleting all workspace
variables and functions; this option instructs ``dynare`` not
to clear the workspace. Note that starting with Matlab 2015b
``dynare`` only deletes the global variables and the functions
using persistent variables, in order to benefit from the JIT
(Just In Time) compilation. In this case the option instructs
``dynare`` not to clear the globals and functions.
.. option:: onlyclearglobals
By default, ``dynare`` will issue a ``clear all`` command to
MATLAB versions before 2015b and to Octave, thereby deleting
all workspace variables; this option instructs ``dynare`` to
clear only the global variables (i.e. ``M_, options_, oo_,
estim_params_, bayestopt_``, and ``dataset_``), leaving the
other variables in the workspace.
.. option:: debug
Instructs the preprocessor to write some debugging information
about the scanning and parsing of the ``.mod`` file.
.. option:: notmpterms
Instructs the preprocessor to omit temporary terms in the
static and dynamic files; this generally decreases
performance, but is used for debugging purposes since it makes
the static and dynamic files more readable.
.. option:: savemacro[=FILENAME]
Instructs ``dynare`` to save the intermediary file which is
obtained after macro processing (see :ref:`macro-proc-lang`);
the saved output will go in the file specified, or if no file
is specified in ``FILENAME-macroexp.mod``
.. option:: onlymacro
Instructs the preprocessor to only perform the
macro processing step, and stop just after. Useful for
debugging purposes or for using the macro processor
independently of the rest of Dynare toolbox.
.. option:: nolinemacro
Instructs the macro preprocessor to omit line numbering
information in the intermediary ``.mod`` file created after
the macro processing step. Useful in conjunction with
:opt:`savemacro <savemacro[=FILENAME]>` when one wants that to reuse the intermediary
``.mod`` file, without having it cluttered by line numbering
directives.
.. option:: noemptylinemacro
Passing this option removes all empty from the macro expanded
mod file created when the :opt:`savemacro <savemacro[=FILENAME]>` option is used.
.. option:: onlymodel
Instructs the preprocessor to print only information about the
model in the driver file; no Dynare commands (other than the
shocks statement and parameter initializations) are printed
and hence no computational tasks performed. The same
ancillary files are created as would otherwise be created
(dynamic, static files, etc.).
.. option:: nolog
Instructs Dynare to no create a logfile of this run in
``FILENAME.log.`` The default is to create the logfile.
.. option:: params_derivs_order=0|1|2
When :comm:`identification`, :comm:`dynare_sensitivity` (with
identification), or :ref:`estimation_cmd <estim-comm>` are
present, this option is used to limit the order of the
derivatives with respect to the parameters that are calculated
by the preprocessor. 0 means no derivatives, 1 means first
derivatives, and 2 means second derivatives. Default: 2
.. option:: nowarn
Suppresses all warnings.
.. option:: json = parse|check|transform|compute
Causes the preprocessor to output a version of the ``.mod`` file in
JSON format. When the JSON output is created depends on the value
passed. These values represent various steps of processing in the
preprocessor.
If ``parse`` is passed, the output will be written after the parsing of
the ``.mod`` file to a file called ``FILENAME.json`` but before file
has been checked (e.g. if there are unused exogenous in the model
block, the JSON output will be created before the preprocessor exits).
If ``check`` is passed, the output will be written to a file called
``FILENAME.json`` after the model has been checked.
If ``transform`` is passed, the JSON output of the transformed
model (maximum lead of 1, minimum lag of -1, expectation
operators substituted, etc.) will be written to a file called
``FILENAME.json`` and the original, untransformed model will
be written in ``FILENAME_original.json``.
And if ``compute`` is passed, the output is written after the
computing pass. In this case, the transformed model is written
to ``FILENAME.json``, the original model is written to
``FILENAME_original.json``, and the dynamic and static files
are written to ``FILENAME_dynamic.json`` and
``FILENAME_static.json``.
.. option:: jsonstdout
Instead of writing output requested by ``json`` to files,
write to standard out.
.. option:: onlyjson
Quit processing once the output requested by ``json`` has been
written.
.. option:: jsonderivsimple
Print a simplified version (excluding variable name(s) and lag
information) of the static and dynamic files in
``FILENAME_static.json`` and ``FILENAME_dynamic.``.
.. option:: warn_uninit
Display a warning for each variable or parameter which is not
initialized. See :ref:`param-init`, or
:comm:`load_params_and_steady_state
<load_params_and_steady_state>` for initialization of
parameters. See :ref:`init-term-cond`, or
:comm:`load_params_and_steady_state
<load_params_and_steady_state>` for initialization of
endogenous and exogenous variables.
.. option:: console
Activate console mode. In addition to the behavior of
``nodisplay``, Dynare will not use graphical waitbars for long
computations.
.. option:: nograph
Activate the ``nograph`` option (see :opt:`nograph`), so that
Dynare will not produce any graph.
.. option:: nointeractive
Instructs Dynare to not request user input.
.. option:: nopathchange
By default Dynare will change Matlab/Octaves path if
``dynare/matlab`` directory is not on top and if Dynares
routines are overriden by routines provided in other
toolboxes. If one wishes to override Dynares routines, the
``nopathchange`` options can be used. Alternatively, the path
can be temporarly modified by the user at the top of the
``.mod`` file (using Matlab/Octaves ``addpath`` command).
.. option:: nopreprocessoroutput
Prevent Dynare from printing the output of the steps leading up to the
preprocessor as well as the preprocessor output itself.
.. option:: mexext=mex|mexw32|mexw64|mexmaci64|mexa64
The mex extension associated with your platform to be used
when compiling output associated with :opt:`use_dll`.
Dynare is able to set this automatically, so you should not
need to set it yourself.
.. option:: matlabroot=<<path>>
The path to the Matlab installation for use with
:opt:`use_dll`. Dynare is able to set this automatically,
so you should not need to set it yourself.
.. option:: parallel[=CLUSTER_NAME]
Tells Dynare to perform computations in parallel. If
CLUSTER_NAME is passed, Dynare will use the specified cluster
to perform parallel computations. Otherwise, Dynare will use
the first cluster specified in the configuration file. See
:ref:`conf-file`, for more information about the configuration
file.
.. option:: conffile=FILENAME
Specifies the location of the configuration file if it differs
from the default. See :ref:`conf-file`, for more information
about the configuration file and its default location.
.. option:: parallel_slave_open_mode
Instructs Dynare to leave the connection to the slave node
open after computation is complete, closing this connection
only when Dynare finishes processing.
.. option:: parallel_test
Tests the parallel setup specified in the configuration file
without executing the ``.mod`` file. See :ref:`conf-file`, for
more information about the configuration file.
.. option:: -DMACRO_VARIABLE=MACRO_EXPRESSION
Defines a macro-variable from the command line (the same
effect as using the Macro directive ``@#define`` in a model
file, see :ref:`macro-proc-lang`).
.. option:: -I<<path>>
Defines a path to search for files to be included by the
macro processor (using the ``@#include`` command). Multiple
``-I`` flags can be passed on the command line. The paths will
be searched in the order that the ``-I`` flags are passed and
the first matching file will be used. The flags passed here
take priority over those passed to ``@#includepath``.
.. option:: nostrict
Allows Dynare to issue a warning and continue processing when
1. there are more endogenous variables than equations.
2. an undeclared symbol is assigned in ``initval`` or ``endval``.
3. an undeclared symbol is found in the ``model`` block in
this case, it is automatically declared exogenous.
4. exogenous variables were declared but not used in the
``model`` block.
.. option:: fast
Only useful with model option ``use_dll``. Dont recompile the
MEX files when running again the same model file and the lists
of variables and the equations havent changed. We use a 32
bit checksum, stored in ``<model filename>/checksum``. There
is a very small probability that the preprocessor misses a
change in the model. In case of doubt, re-run without the fast
option.
.. option:: minimal_workspace
Instructs Dynare not to write parameter assignments to
parameter names in the .m file produced by the
preprocessor. This is potentially useful when running
``dynare`` on a large ``.mod`` file that runs into workspace
size limitations imposed by MATLAB.
.. option:: compute_xrefs
Tells Dynare to compute the equation cross references, writing
them to the output ``.m`` file.
.. option:: stochastic
Tells Dynare that the model to be solved is stochastic. If no
Dynare commands related to stochastic models (``stoch_simul``,
``estimation``, ...) are present in the ``.mod`` file, Dynare
understands by default that the model to be solved is
deterministic.
These options can be passed to the preprocessor by listing them
after the name of the ``.mod`` file. They can alternatively be
defined in the first line of the ``.mod`` file, this avoids typing
them on the command line each time a ``.mod`` file is to be
run. This line must be a Dynare comment (ie must begin with //)
and the options must be comma separated between ``--+`` options:
and ``+--``. Note that any text after the ``+--`` will be
discarded. As in the command line, if an option admits a value the
equal symbol must not be surrounded by spaces. For instance ``json
= compute`` is not correct, and should be written
``json=compute``.
*Output*
Depending on the computing tasks requested in the ``.mod`` file,
executing the ``dynare`` command will leave variables containing
results in the workspace available for further processing. More
details are given under the relevant computing tasks. The
``M_``,``oo_``, and ``options_`` structures are saved in a file
called ``FILENAME_results.mat``. If they exist, ``estim_params_``,
``bayestopt_``, ``dataset_``, ``oo_recursive_`` and
``estimation_info`` are saved in the same file.
.. matvar:: M_
Structure containing various information about the model.
.. matvar:: options_
Structure contains the values of the various options used by
Dynare during the computation.
.. matvar:: oo_
Structure containing the various results of the computations.
.. matvar:: dataset_
A ``dseries`` object containing the data used for estimation.
.. matvar:: oo_recursive_
Cell array containing the ``oo_`` structures obtained when
estimating the model for the different samples when performing
recursive estimation and forecasting. The ``oo_`` structure
obtained for the sample ranging to the `i` -th observation is
saved in the `i` -th field. The fields for non-estimated
endpoints are empty.
*Example*
Call dynare from the MATLAB or Octave prompt, without or with options:
.. code-block:: matlab
>> dynare ramst
>> dynare ramst.mod savemacro
Alternatively the options can be passed in the first line of
``ramst.mod``:
.. code-block:: dynare
// --+ options: savemacro, json=compute +--
and then dynare called without passing options on the command line:
.. code-block:: matlab
>> dynare ramst
Dynare hooks
============
It is possible to call pre and post Dynare preprocessor hooks written
as MATLAB scripts. The script ``MODFILENAME/hooks/priorprocessing.m``
is executed before the call to Dynares preprocessor, and can be used
to programmatically transform the mod file that will be read by the
preprocessor. The script ``MODFILENAME/hooks/postprocessing.m`` is
gexecuted just after the call to Dynares preprocessor, and can be used
to programmatically transform the files generated by Dynares
preprocessor before actual computations start. The pre and/or post
dynare preprocessor hooks are executed if and only if the
aforementioned scripts are detected in the same folder as the the
model file, ``FILENAME.mod``.
Understanding Preprocessor Error Messages
=========================================
If the preprocessor runs into an error while processing your ``.mod``
file, it will issue an error. Due to the way that a parser works,
sometimes these errors can be misleading. Here, we aim to demystify
these error messages.
The preprocessor issues error messages of the form:
#. ``ERROR: <<file.mod>>: line A, col B: <<error message>>``
#. ``ERROR: <<file.mod>>: line A, cols B-C: <<error message>>``
#. ``ERROR: <<file.mod>>: line A, col B - line C, col D: <<error message>>``
The first two errors occur on a single line, with error two spanning
multiple columns. Error three spans multiple rows.
Often, the line and column numbers are precise, leading you directly
to the offending syntax. Infrequently however, because of the way the
parser works, this is not the case. The most common example of
misleading line and column numbers (and error message for that matter)
is the case of a missing semicolon, as seen in the following example::
varexo a, b
parameters c, ...;
In this case, the parser doesnt know a semicolon is missing at the
end of the ``varexo`` command until it begins parsing the second line
and bumps into the ``parameters`` command. This is because we allow
commands to span multiple lines and, hence, the parser cannot know
that the second line will not have a semicolon on it until it gets
there. Once the parser begins parsing the second line, it realizes
that it has encountered a keyword, ``parameters``, which it did not
expect. Hence, it throws an error of the form: ``ERROR: <<file.mod>>:
line 2, cols 0-9: syntax error, unexpected PARAMETERS``. In this case,
you would simply place a semicolon at the end of line one and the
parser would continue processing.
It is also helpful to keep in mind that any piece of code that does not violate
Dynare syntax, but at the same time is not recognized by the parser, is interpreted
as native Matlab code. This code will be directly passed to the ``driver`` script.
Investigating ``driver.m`` file then helps with debugging. Such problems most often
occur when defined variable or parameter names have been misspelled so that Dynare's
parser is unable to recognize them.

View File

@ -0,0 +1,389 @@
.. default-domain:: dynare
.. |br| raw:: html
<br>
.. _conf-file:
######################
The configuration file
######################
The configuration file is used to provide Dynare with information not
related to the model (and hence not placed in the model file). At the
moment, it is only used when using Dynare to run parallel
computations.
On Linux and macOS, the default location of the configuration file is
``$HOME/.dynare``, while on Windows it is ``%APPDATA%\dynare.ini``
(typically ``c:\Users\USERNAME\AppData\dynare.ini``). You
can specify a non standard location using the ``conffile`` option of
the ``dynare`` command (see :ref:`dyn-invoc`).
The parsing of the configuration file is case-sensitive and it should
take the following form, with each option/choice pair placed on a
newline::
[command0]
option0 = choice0
option1 = choice1
[command1]
option0 = choice0
option1 = choice1
The configuration file follows a few conventions (self-explanatory
conventions such as ``USER_NAME`` have been excluded for concision):
``COMPUTER_NAME``
Indicates the valid name of a server (e.g. ``localhost``,
``server.cepremap.org``) or an IP address.
``DRIVE_NAME``
Indicates a valid drive name in Windows, without the trailing
colon (e.g. ``C``).
``PATH``
Indicates a valid path in the underlying operating system
(e.g. ``/home/user/dynare/matlab/``).
``PATH_AND_FILE``
Indicates a valid path to a file in the underlying operating
system (e.g. ``/usr/local/MATLAB/R2010b/bin/matlab``).
``BOOLEAN``
Is ``true`` or ``false``.
Dynare Configuration
====================
This section explains how to configure Dynare for general
processing. Currently, there is only one option available.
.. confblock:: [hooks]
|br| This block can be used to specify configuration options that will
be used when running Dynare.
*Options*
.. option:: GlobalInitFile = PATH_AND_FILE
The location of the global initialization file to be run at
the end of ``global_initialization.m``.
*Example*
::
[hooks]
GlobalInitFile = /home/usern/dynare/myInitFile.m
.. confblock:: [paths]
|br| This block can be used to specify paths that will be used
when running dynare.
*Options*
.. option:: Include = PATH
A colon-separated path to use when searching for files to
include via ``@#include``. Paths specified via :opt:`-I
<-I\<\<path\>\>>` take priority over paths specified here,
while these paths take priority over those specified by
``@#includepath``.
*Example*
::
[paths]
Include = /path/to/folder/containing/modfiles:/path/to/another/folder
.. _paral-conf:
Parallel Configuration
======================
This section explains how to configure Dynare for parallelizing some
tasks which require very little inter-process communication.
The parallelization is done by running several MATLAB or Octave
processes, either on local or on remote machines. Communication
between master and slave processes are done through SMB on Windows and
SSH on UNIX. Input and output data, and also some short status
messages, are exchanged through network filesystems. Currently the
system works only with homogenous grids: only Windows or only Unix
machines.
The following routines are currently parallelized:
* the posterior sampling algorithms when using multiple chains;
* the Metropolis-Hastings diagnostics;
* the posterior IRFs;
* the prior and posterior statistics;
* some plotting routines.
Note that creating the configuration file is not enough in order to
trigger parallelization of the computations: you also need to specify
the ``parallel`` option to the ``dynare`` command. For more details,
and for other options related to the parallelization engine, see
:ref:`dyn-invoc`.
You also need to verify that the following requirements are met by
your cluster (which is composed of a master and of one or more
slaves):
For a Windows grid:
* a standard Windows network (SMB) must be in place;
* the `PsTools`_ suite must be installed in the path of the
master Windows machine;
* the Windows user on the master machine has to be user of any
other slave machine in the cluster, and that user will be
used for the remote computations.
* detailed step-by-step setup instructions can be found in
:ref:`win-ssg`.
For a UNIX grid:
* SSH must be installed on the master and on the slave machines;
* SSH keys must be installed so that the SSH connection from
the master to the slaves can be done without passwords, or
using an SSH agent.
We now turn to the description of the configuration directives. Note
that comments in the configuration file can be provided by separate
lines starting with a hashtag (#).
.. confblock:: [cluster]
|br| When working in parallel, ``[cluster]`` is required to specify the
group of computers that will be used. It is required even if you
are only invoking multiple processes on one computer.
*Options*
.. option:: Name = CLUSTER_NAME
The reference name of this cluster.
.. option:: Members = NODE_NAME[(WEIGHT)] NODE_NAME[(WEIGHT)] ...
A list of nodes that comprise the cluster with an optional
computing weight specified for that node. The computing weight
indicates how much more powerful one node is with respect to
the others (e.g. ``n1(2) n2(1) n3(3)`` means that ``n1`` is
two times more powerful than ``n2`` whereas ``n3`` is three
times more powerful than ``n2``). Each node is separated by at
least one space and the weights are in parenthesis with no
spaces separating them from their node.
*Example*
::
[cluster]
Name = c1
Members = n1 n2 n3
[cluster]
Name = c2
Members = n1(4) n2 n3
.. confblock:: [node]
|br| When working in parallel, ``[node]`` is required for every
computer that will be used. The options that are required differ,
depending on the underlying operating system and whether you are
working locally or remotely.
*Options*
.. option:: Name = NODE_NAME
The reference name of this node.
.. option:: CPUnbr = INTEGER | [INTEGER:INTEGER]
If just one integer is passed, the number of processors to
use. If a range of integers is passed, the specific processors
to use (processor counting is defined to begin at one as
opposed to zero). Note that using specific processors is only
possible under Windows; under Linux and macOS, if a range is
passed the same number of processors will be used but the
range will be adjusted to begin at one.
.. option:: ComputerName = COMPUTER_NAME
The name or IP address of the node. If you want to run
locally, use ``localhost`` (case-sensitive).
.. option:: Port = INTEGER
The port number to connect to on the node. The default is
empty, meaning that the connection will be made to the default
SSH port (22).
.. option:: UserName = USER_NAME
The username used to log into a remote system. Required for
remote runs on all platforms.
.. option:: Password = PASSWORD
The password used to log into the remote system. Required for
remote runs originating from Windows.
.. option:: RemoteDrive = DRIVE_NAME
The drive to be used for remote computation. Required for
remote runs originating from Windows.
.. option:: RemoteDirectory = PATH
The directory to be used for remote computation. Required for
remote runs on all platforms.
.. option:: DynarePath = PATH
The path to the matlab subdirectory within the Dynare
installation directory. The default is the empty string.
.. option:: MatlabOctavePath = PATH_AND_FILE
The path to the MATLAB or Octave executable. The default value
is ``matlab``.
.. option:: NumberOfThreadsPerJob = INTEGER
For Windows nodes, sets the number of threads assigned to each
remote MATLAB/Octave run. The default value is 1.
.. option:: SingleCompThread = BOOLEAN
Whether or not to disable MATLABs native multithreading. The
default value is ``false``. Option meaningless under Octave.
.. option:: OperatingSystem = OPERATING_SYSTEM
The operating system associated with a node. Only necessary
when creating a cluster with nodes from different operating
systems. Possible values are ``unix`` or ``windows``. There is
no default value.
*Example*
::
[node]
Name = n1
ComputerName = localhost
CPUnbr = 1
[node]
Name = n2
ComputerName = dynserv.cepremap.org
CPUnbr = 5
UserName = usern
RemoteDirectory = /home/usern/Remote
DynarePath = /home/usern/dynare/matlab
MatlabOctavePath = matlab
[node]
Name = n3
ComputerName = dynserv.dynare.org
Port = 3333
CPUnbr = [2:4]
UserName = usern
RemoteDirectory = /home/usern/Remote
DynarePath = /home/usern/dynare/matlab
MatlabOctavePath = matlab
.. _win-ssg:
Windows Step-by-Step Guide
==========================
This section outlines the steps necessary on most Windows systems to
set up Dynare for parallel execution.
1. Write a configuration file containing the options you want. A
mimimum working example setting up a cluster consisting of two
local CPU cores that allows for e.g. running two Monte Carlo
Markov Chains in parallel is shown below.
2. Save the configuration file somwhere. The name and file ending
do not matter if you are providing it with the ``conffile``
command line option. The only restrictions are that the path
must be a valid filename, not contain non-alpha-numeric
characters, and not contain any whitespaces. For the
configuration file to be accessible without providing an
explicit path at the command line, you must save it under the
name ``dynare.ini`` into your user accounts ``Application
Data`` folder.
3. Install `PSTools`_ to your system, e.g. into ``C:\PSTools.``
4. Set the Windows System Path to the ``PSTools`` folder
(e.g. using something along the line of pressing Windows
Key+Pause to open the System Configuration, then go to Advanced
-> Environment Variables -> Path).
5. Restart your computer to make the path change effective.
6. Open Matlab and type into the command window::
!psexec
This executes the ``psexec.exe`` from PSTools on your system
and shows whether Dynare will be able to locate it. If Matlab
complains at this stage, you did not correctly set your Windows
system path for the ``PSTools`` folder.
7. If ``psexec.exe`` was located in the previous step, a popup
will show up, asking for confirmation of the license
agreement. Confirm this copyright notice of ``psexec`` (this
needs to be done only once). After this, Dynare should be ready
for parallel execution.
8. Call Dynare on your mod-file invoking the ``parallel`` option
and providing the path to your configuration file with the
``conffile`` option (if you did not save it as
``%APPDATA%\dynare.ini`` in step 2 where it should be detected
automatically)::
dynare ls2003 parallel conffile='C:\Users\Dynare~1\parallel\conf_file.ini'
Please keep in mind that no white spaces or names longer than 8
characters are allowed in the ``conffile`` path. The 8-character
restriction can be circumvented by using the tilde Windows path
notation as in the above example.
*Example*::
#cluster needs to always be defined first
[cluster]
#Provide a name for the cluster
Name=Local
#declare the nodes being member of the cluster
Members=n1
#declare nodes (they need not all be part of a cluster)
[node]
#name of the node
Name=n1
#name of the computer (localhost for the current machine)
ComputerName=localhost
#cores to be included from this node
CPUnbr=[1:2]
#path to matlab.exe; on Windows, theMatlab bin folder is in the system path
#so we only need to provide the name of the exe file
MatlabOctavePath=matlab
#Dynare path you are using
DynarePath=C:/dynare/2016-05-10/matlab
.. _PsTools: https://technet.microsoft.com/sysinternals/pstools.aspx

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,376 @@
# -*- coding: utf-8 -*-
# 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/>.
"""
sphinx.domains.dynare
~~~~~~~~~~~~~~~~~~~~~
The Dynare domain.
Loosely based on the JavaScript domain from the Sphinx team and the CoffeScript domain
by Stephen Sugden (available at sphinx-contrib)
"""
import re
from docutils import nodes
from docutils.parsers.rst import Directive, directives
from sphinx import addnodes
from sphinx.domains import Domain, ObjType
from sphinx.locale import l_, _
from sphinx.directives import ObjectDescription
from sphinx.roles import XRefRole
from sphinx.util.nodes import make_refnode
from sphinx.util.docfields import Field, GroupedField, TypedField
############### Dynare Object types #######################
class DynObject(ObjectDescription):
has_arguments = True
display_prefix = None
allow_nesting = False
def handle_signature(self, sig, signode):
sig = sig.strip()
# Some variable/parameter declarations combine spaces and parenthesis
# in a strange way, so they are treated separately
if sig.startswith(('var V','varexo V','varexo_det V','parameters P','model_comparison F')):
member = sig[:sig.index(' ')]
arglist = sig[sig.index(' '):]
# General cases
elif '(' in sig:
member = sig[:sig.index('(')]
arglist = sig[sig.index('('):]
arglist = arglist.strip()
elif ' ' in sig:
member = sig[:sig.index(' ')]
arglist = sig[sig.index(' '):]
else:
member = sig
arglist = None
prefix = self.env.ref_context.get('dynare:object', None)
name = member.strip()
fullname = name
signode['object'] = prefix
signode['fullname'] = fullname
if self.display_prefix:
signode += addnodes.desc_annotation(self.display_prefix, self.display_prefix)
signode += addnodes.desc_name(name, name)
if self.has_arguments:
if not arglist:
signode += addnodes.desc_parameterlist()
else:
signode += addnodes.desc_addname(arglist,arglist)
return fullname, prefix
def add_target_and_index(self, name_obj, sig, signode):
fullname = name_obj[0]
if fullname not in self.state.document.ids:
signode['names'].append(fullname)
signode['ids'].append(fullname)
signode['first'] = not self.names
self.state.document.note_explicit_target(signode)
objects = self.env.domaindata['dynare']['objects']
if fullname in objects:
self.state_machine.reporter.warning(
'duplicate object description of %s, ' % fullname +
'other instance in ' +
self.env.doc2path(objects[fullname][0]),line=self.lineno)
objects[fullname] = (self.env.docname, self.objtype)
indextext = self.get_index_text(fullname,name_obj)
if indextext:
self.indexnode['entries'].append(('single', indextext, fullname,'', None))
def get_index_text(self, objectname, name_obj):
name, obj = name_obj
regexp = re.compile(r'\s*=\s*')
if bool(regexp.search(name)):
aux, name = re.compile(r'\s*=\s*').split(name)
if self.objtype == 'function':
return _('%s (function)') % name
elif self.objtype == 'class':
return _('%s (class)') % name
elif self.objtype == 'datesmethod':
return _('%s (dates method)') % name
elif self.objtype == 'dseriesmethod':
return _('%s (dseries method)') % name
elif self.objtype == 'reportingmethod':
return _('%s (reporting method)') % name
elif self.objtype == 'matcomm':
return _('%s (MATLAB command)') % name
elif self.objtype == 'command':
return _('%s (command)') % name
elif self.objtype == 'block':
return _('%s (block)') % name
elif self.objtype == 'confblock':
name = name[1:-1]
return _('%s (config block)') % name
elif self.objtype == 'macrodir':
name = name[2:]
return _('%s (macro directive)') % name
class DynCallable(DynObject):
has_arguments = True
doc_field_types = [
TypedField('arguments', label=l_('Arguments'),
names=('argument', 'arg', 'parameter', 'param'),
typerolename='func', typenames=('paramtype', 'type')),
Field('returnvalue', label=l_('Returns'), has_arg=False,
names=('returns', 'return')),
Field('returntype', label=l_('Return type'), has_arg=False,
names=('rtype',)),
Field('example', label=l_('Example'), has_arg=False,
names=('ex',)),
]
class DynClass(DynObject):
has_arguments = False
display_prefix = 'Dynare class: '
allow_nesting = True
doc_field_types = [
TypedField('members', label=l_('Members'),
names=('argument', 'arg', ),
typerolename='func', typenames=('type', )),
Field('example', label=l_('Example'), has_arg=False,
names=('ex',)),
]
class DynFunction(DynCallable):
display_prefix = 'Function: '
allow_nesting = True
class DatesMethod(DynCallable):
display_prefix = 'Method: '
allow_nesting = True
class DseriesMethod(DynCallable):
display_prefix = 'Method: '
allow_nesting = True
class ReportingMethod(DynCallable):
display_prefix = 'Method: '
allow_nesting = True
class MatComm(DynCallable):
display_prefix = 'MATLAB/Octave command: '
allow_nesting = False
class DynComm(DynCallable):
display_prefix = 'Command: '
allow_nesting = False
class DynBlock(DynCallable):
display_prefix = 'Block: '
allow_nesting = False
class DynConfBlock(DynCallable):
display_prefix = 'Configuration block: '
has_arguments = False
allow_nesting = False
class DynMacroDir(DynCallable):
display_prefix = 'Macro directive: '
allow_nesting = False
class Constructor(DynCallable):
display_prefix = 'Constructor: '
allow_nesting = False
class DynSimpleObject(ObjectDescription):
has_arguments = False
allow_nesting = False
def handle_signature(self, sig, signode):
sig = sig.strip()
member = sig
arglist = None
prefix = self.env.ref_context.get('dynare:object', None)
name = member
fullname = name
signode['object'] = prefix
signode['fullname'] = fullname
if self.display_prefix:
signode += addnodes.desc_annotation(self.display_prefix, self.display_prefix)
signode += addnodes.desc_name(name, name)
return fullname, prefix
def add_target_and_index(self, name_obj, sig, signode):
fullname = name_obj[0]
if fullname not in self.state.document.ids:
signode['names'].append(fullname)
signode['ids'].append(fullname)
signode['first'] = not self.names
self.state.document.note_explicit_target(signode)
objects = self.env.domaindata['dynare']['objects']
if fullname in objects:
self.state_machine.reporter.warning(
'duplicate object description of %s, ' % fullname +
'other instance in ' +
self.env.doc2path(objects[fullname][0]), line=self.lineno)
objects[fullname] = self.env.docname, self.objtype
indextext = self.get_index_text(fullname,name_obj)
if indextext:
self.indexnode['entries'].append(('single', indextext, fullname,'', None))
def get_index_text(self, objectname, name_obj):
name, obj = name_obj
if self.objtype == 'construct':
name, rest = name.split(' ',1)
return _('%s (constructor)') % name
elif self.objtype == 'matvar':
return _('%s (MATLAB variable)') % name
elif self.objtype == 'specvar':
return _('%s (special variable)') % name
elif self.objtype == 'operator':
endsig = name.find(' ')
name = name[0:endsig]
return _('%s (operator)') % name
elif self.objtype == 'constant':
return _('%s (constant)') % name
class MatlabVar(DynSimpleObject):
display_prefix = 'MATLAB/Octave variable: '
allow_nesting = False
class SpecialVar(MatlabVar):
display_prefix = 'Special variable: '
class Operator(MatlabVar):
display_prefix = 'Operator: '
class Constant(MatlabVar):
display_prefix = 'Constant: '
class Option(MatlabVar):
display_prefix = None
############## Cross-referencing ####################
class DynareXRefRole(XRefRole):
def process_link(self, env, refnode, has_explicit_title, title, target):
refnode['dynare:object'] = env.ref_context.get('dynare:object')
return title, target
############### Dynare domain #######################
class DynareDomain(Domain):
name = 'dynare'
label = 'Dynare'
object_types = {
'function': ObjType(l_('function'), 'func'),
'datesmethod': ObjType(l_('method'), 'datmeth'),
'dseriesmethod': ObjType(l_('method'), 'dsermeth'),
'reportingmethod': ObjType(l_('method'), 'repmeth'),
'matcomm': ObjType(l_('matlab command'), 'mcomm'),
'command': ObjType(l_('command'), 'comm'),
'class': ObjType(l_('class'), 'class'),
'block': ObjType(l_('block'), 'bck'),
'confblock': ObjType(l_('config block'), 'cbck'),
'macrodir': ObjType(l_('macro directive'), 'mdir'),
'construct': ObjType(l_('constructor'), 'cstr'),
'matvar': ObjType(l_('matlab variable'), 'mvar'),
'specvar': ObjType(l_('special variable'), 'svar'),
'operator': ObjType(l_('operator'), 'op'),
'constant': ObjType(l_('constant'), 'const'),
'option': ObjType(l_('option'), 'opt'),
}
directives = {
'function': DynFunction,
'datesmethod': DatesMethod,
'dseriesmethod': DseriesMethod,
'reportingmethod': ReportingMethod,
'matcomm': MatComm,
'command': DynComm,
'class': DynClass,
'block': DynBlock,
'confblock': DynConfBlock,
'macrodir': DynMacroDir,
'construct': Constructor,
'matvar': MatlabVar,
'specvar': SpecialVar,
'operator': Operator,
'constant': Constant,
'option': Option,
}
roles = {
'func': DynareXRefRole(),
'datmeth': DynareXRefRole(),
'dsermeth': DynareXRefRole(),
'repmeth': DynareXRefRole(),
'mcomm': DynareXRefRole(),
'comm': DynareXRefRole(),
'class': DynareXRefRole(),
'bck': DynareXRefRole(),
'cbck': DynareXRefRole(),
'mdir': DynareXRefRole(),
'cstr': DynareXRefRole(),
'mvar': DynareXRefRole(),
'svar': DynareXRefRole(),
'op': DynareXRefRole(),
'const': DynareXRefRole(),
'opt': DynareXRefRole(),
}
initial_data = {
'objects': {},
}
def clear_doc(self, docname):
for fullname, (fn, _l) in list(self.data['objects'].items()):
if fn == docname:
del self.data['objects'][fullname]
def find_obj(self, env, obj, name, typ, searchorder=0):
objects = self.data['objects']
newname = name # None
return newname, objects.get(newname)
def merge_domaindata(self, docnames, otherdata):
for fullname, (fn, objtype) in otherdata['objects'].items():
if fn in docnames:
self.data['objects'][fullname] = (fn, objtype)
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
objectname = node.get('dynare:object')
searchorder = node.hasattr('refspecific') and 1 or 0
name, obj = self.find_obj(env, objectname, target, typ, searchorder)
if not obj:
return None
return make_refnode(builder, fromdocname, obj[0], name, contnode, name)
def get_objects(self):
for refname, (docname, type) in list(self.data['objects'].items()):
yield refname, refname, type, docname, refname, 1

View File

@ -0,0 +1,111 @@
# 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/>.
import re
from pygments.lexer import Lexer, RegexLexer, bygroups, do_insertions, words
from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
Number, Punctuation, Generic, Whitespace
# Configuration block :BOLD
#conf_blocks = ('hooks','paths','cluster','node')
__all__ = ['DynareLexer']
class DynareLexer(RegexLexer):
name = 'Dynare'
aliases = ['dynare']
filenames = ['*.mod']
commands = (
"dynare","var","varexo","varexo_det","parameters","change_type","model_local_variable",
"predetermined_variables","trend_var","log_trend_var","external_function",
"write_latex_original_model","write_latex_dynamic_model",
"write_latex_static_model","resid","initval_file","histval_file","dsample",
"periods","values","corr","steady","check","model_diagnostics","model_info",
"print_bytecode_dynamic_model"," print_bytecode_static_model",
"perfect_foresight_setup","perfect_foresight_solver","simul","stoch_simul",
"extended_path","varobs","estimation","unit_root_vars","bvar_density",
"model_comparison","shock_decomposition","realtime_shock_decomposition",
"plot_shock_decomposition","calib_smoother","forecast",
"conditional_forecast","plot_conditional_forecast","bvar_forecast",
"smoother2histval","osr","osr_params","ramsey_model","ramsey_policy",
"discretionary_policy","planner_objective","dynare_sensitivity",
"markov_switching","svar","sbvar","ms_estimation","ms_simulation",
"ms_compute_mdd","ms_compute_probabilities","ms_irf","ms_forecast",
"ms_variance_decomposition","rplot","dynatype","dynasave","set_dynare_seed",
"save_params_and_steady_state","load_params_and_steady_state",
"dynare_version","write_latex_definitions","write_latex_parameter_table",
"write_latex_prior_table","collect_latex_files","prior_function",
"posterior_function","generate_trace_plots")
report_commands = ("report","addPage","addSection","addGraph","addTable",
"addSeries","addParagraph","addVspace","write","compile")
operators = (
"STEADY_STATE","EXPECTATION")
macro_dirs = (
"@#includepath", "@#include", "@#define", "@#if",
"@#ifdef", "@#ifndef", "@#else","@#endif",
"@#for", "@#endfor", "@#echo", "@#error")
builtin_constants = (
"inf", "nan")
tokens = {
'root': [
(r'\s*(%|//).*$', Comment),
(words((
'model','steady_state_model','initval','endval','histval',
'shocks','mshocks','homotopy_setup','observation_trends',
'estimated_params','estimated_params_init','estimated_params_bounds',
'shock_groups','conditional_forecast_paths','optim_weights',
'osr_params_bounds','ramsey_constraints','irf_calibration',
'moment_calibration','identification','svar_identification',
'verbatim','end','node','cluster','paths','hooks'), prefix=r'\b', suffix=r'\s*\b'),Keyword.Reserved),
(words(commands + report_commands,
prefix=r'\b', suffix=r'\s*\b'), Name.Entity),
(words(operators), Operator.Word),
(words(macro_dirs,suffix=r'\s*'), Name.Function),
(words(builtin_constants), Name.Constant),
(r'\s*[a-zA-Z_]\s*', Name),
(r'\s*(\d+\.\d+|\d*\.\d+)([eEf][+-]?[0-9]+)?\s*', Number.Float),
(r'\s*\d+[eEf][+-]?[0-9]+\s*', Number.Float),
(r'\s*\d+\s*', Number.Integer),
(r'"[^"]*"', String),
(r"`[^`]*'", String),
(r"'[^']*'", String),
(r'\s*(-|\+|\*|\/|\^)\s*', Operator),
(r'\s*(==|<=|>=|~=|<|>|&&|!)\s*', Operator),
(r'\s*[\[\](){}:@.,\|]\s*', Punctuation),
(r'\s*(=|:|;|>>|#|\$)\s*', Punctuation),
]
}

View File

@ -0,0 +1,2 @@
version = u'@PACKAGE_VERSION@'
release = u'@PACKAGE_VERSION@'

View File

@ -1,3 +1 @@
SUBDIRS = sylv parser/cc tl doc utils/cc integ kord src
EXTRA_DIST = change_log.html c++lib.w tests extern
SUBDIRS = utils/cc sylv parser/cc tl doc integ kord src tests

View File

@ -1,85 +0,0 @@
@q This file defines standard C++ namespaces and classes @>
@q Please send corrections to saroj-tamasa@@worldnet.att.net @>
@s std int
@s rel_ops int
@s bitset int
@s char_traits int
@s deque int
@s list int
@s map int
@s multimap int
@s multiset int
@s pair int
@s set int
@s stack int
@s exception int
@s logic_error int
@s runtime_error int
@s domain_error int
@s invalid_argument int
@s length_error int
@s out_of_range int
@s range_error int
@s overflow_error int
@s underflow_error int
@s back_insert_iterator int
@s front_insert_iterator int
@s insert_iterator int
@s reverse_iterator int
@s istream_iterator int
@s ostream_iterator int
@s istreambuf_iterator int
@s ostreambuf_iterator int
@s iterator_traits int
@s queue int
@s vector int
@s basic_string int
@s string int
@s auto_ptr int
@s valarray int
@s ios_base int
@s basic_ios int
@s basic_streambuf int
@s basic_istream int
@s basic_ostream int
@s basic_iostream int
@s basic_stringbuf int
@s basic_istringstream int
@s basic_ostringstream int
@s basic_stringstream int
@s basic_filebuf int
@s basic_ifstream int
@s basic_ofstream int
@s basic_fstream int
@s ctype int
@s collate int
@s collate_byname int
@s streambuf int
@s istream int
@s ostream int
@s iostream int
@s stringbuf int
@s istringstream int
@s ostringstream int
@s stringstream int
@s filebuf int
@s ifstream int
@s ofstream int
@s fstream int
@s wstreambuf int
@s wistream int
@s wostream int
@s wiostram int
@s wstringbuf int
@s wistringstream int
@s wostringstream int
@s wstringstream int
@s wfilebuf int
@s wifstream int
@s wofstream int
@s wfstream int
@s streamoff int
@s streamsize int
@s fpos int
@s streampos int
@s wstreampos int

View File

@ -1,7 +1,13 @@
EXTRA_DIST = dynare++-ramsey.tex dynare++-tutorial.tex
EXTRA_DIST = \
dynare++-ramsey.tex \
dynare++-tutorial.tex \
sylvester.tex \
tl.tex \
changelog-old.html \
changelog-sylv-old.html
if HAVE_PDFLATEX
pdf-local: dynare++-ramsey.pdf dynare++-tutorial.pdf
pdf-local: dynare++-ramsey.pdf dynare++-tutorial.pdf sylvester.pdf tl.pdf
endif
%.pdf: %.tex

View File

@ -1033,12 +1033,8 @@ default.
threads. Complex evaluations of Faa Di Bruno formulas, simulations and
numerical integration can be parallelized, Dynare++ exploits this
advantage. You have to have a hardware support for this, otherwise
there is no gain from the parallelization. As a rule of thumb, set the
number of threads to the number of processors. An exception is a
machine with Pentium 4 with Hyper Threading (abbreviated by HT). This
processor can run two threads concurrently. The same applies to
Dual-Core processors. Since these processors are present in most new
PC desktops/laptops, the default is 2.
there is no gain from the parallelization. The default value is the number of
logical processors present on the machine, divided by 2.
\item[\desc{\tt --ss-tol \it float}] This sets the tolerance of the
non-linear solver of deterministic steady state to {\it float}. It is

View File

@ -1,20 +1,27 @@
\input amstex
\documentstyle{amsppt}
\def\vec{\mathop{\hbox{vec}}}
\def\otimesi{\mathop{\overset{\ssize i}\to{\otimes}}}
\def\iF{\,^i\!F}
\def\imF{\,^{i-1}\!F}
\def\solvi{\bold{solv1}}
\def\solvii{\bold{solv2}}
\def\solviip{\bold{solv2p}}
\documentclass[11pt,a4paper]{article}
\topmatter
\title Solution of Specialized Sylvester Equation\endtitle
\author Ondra Kamenik\endauthor
\email ondrej.kamenik@cnb.cz\endemail
\endtopmatter
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{fullpage}
\begin{document}
\title{Solution of Specialized Sylvester Equation}
\author{Ondra Kamenik}
\date{2004}
\maketitle
\renewcommand{\vec}{\mathop{\hbox{vec}}}
\newcommand{\otimesi}{\mathop{\overset{i}{\otimes}}}
\newcommand{\iF}{\,^i\!F}
\newcommand{\imF}{\,^{i-1}\!F}
\newcommand{\solvi}{\mathbf{solv1}}
\newcommand{\solvii}{\mathbf{solv2}}
\newcommand{\solviip}{\mathbf{solv2p}}
\newtheorem{lemma}{Lemma}
\document
Given the following matrix equation
$$AX+BX\left(\otimesi C\right)=D,$$ where $A$ is regular $n\times n$
matrix, $X$ is $n\times m^i$ matrix of unknowns, $B$ is singular
@ -36,173 +43,168 @@ and vectorized
$$\left(I+\otimesi F^T\otimes K\right)\vec(Y)=\vec(\widehat{D})$$
Let $\iF$ denote $\otimesi F^T$ for the rest of the text.
\proclaim{Lemma 1}
\section{Preliminary results}
\begin{lemma}
\label{sylv:first-lemma}
For any $n\times n$ matrix $A$ and $\beta_1\beta_2>0$, if there is
exactly one solution of
$$\left(I_2\otimes I_n +
\pmatrix\alpha&\beta_1\cr-\beta_2&\alpha\endpmatrix
\otimes A\right)\pmatrix x_1\cr x_2\endpmatrix =
\pmatrix d_1\cr d_2\endpmatrix,$$
\begin{pmatrix}\alpha&\beta_1\cr-\beta_2&\alpha\end{pmatrix}
\otimes A\right)\begin{pmatrix} x_1\cr x_2\end{pmatrix} =
\begin{pmatrix} d_1\cr d_2\end{pmatrix},$$
then it can be obtained as solution of
$$\align
\begin{align*}
\left(I_n + 2\alpha A+(\alpha^2+\beta^2)A^2\right)x_1 & =
\widehat{d_1}\\
\left(I_n + 2\alpha A+(\alpha^2+\beta^2)A^2\right)x_2 & =
\widehat{d_2}
\endalign$$
\end{align*}
where $\beta=\sqrt{\beta1\beta2}$, and
$$
\pmatrix \widehat{d_1}\cr\widehat{d_2}\endpmatrix =
\begin{pmatrix} \widehat{d_1}\cr\widehat{d_2}\end{pmatrix} =
\left(I_2\otimes I_n +
\pmatrix\alpha&-\beta_1\cr\beta_2&\alpha\endpmatrix
\otimes A\right)\pmatrix d_1\cr d_2\endpmatrix$$
\endproclaim
\begin{pmatrix}\alpha&-\beta_1\cr\beta_2&\alpha\end{pmatrix}
\otimes A\right)\begin{pmatrix} d_1\cr d_2\end{pmatrix}$$
\end{lemma}
\demo{Proof} Since
\begin{proof} Since
$$
\pmatrix \alpha&\beta_1\cr-\beta_2&\alpha\endpmatrix
\pmatrix \alpha&-\beta_1\cr\beta_2&\alpha\endpmatrix
\begin{pmatrix} \alpha&\beta_1\cr-\beta_2&\alpha\end{pmatrix}
\begin{pmatrix} \alpha&-\beta_1\cr\beta_2&\alpha\end{pmatrix}
=
\pmatrix \alpha&-\beta_1\cr\beta_2&\alpha\endpmatrix
\pmatrix \alpha&\beta_1\cr-\beta_2&\alpha\endpmatrix
\begin{pmatrix} \alpha&-\beta_1\cr\beta_2&\alpha\end{pmatrix}
\begin{pmatrix} \alpha&\beta_1\cr-\beta_2&\alpha\end{pmatrix}
=
\pmatrix \alpha^2+\beta^2&0\cr 0&\alpha^2+\beta^2\endpmatrix,
\begin{pmatrix} \alpha^2+\beta^2&0\cr 0&\alpha^2+\beta^2\end{pmatrix},
$$
it is easy to see that if the equation is multiplied by
$$I_2\otimes I_n +
\pmatrix\alpha&-\beta_1\cr\beta_2&\alpha\endpmatrix
\begin{pmatrix}\alpha&-\beta_1\cr\beta_2&\alpha\end{pmatrix}
\otimes A$$
we obtain the result. We only need to prove that the matrix is
regular. But this is clear because matrix
$$\pmatrix \alpha&-\beta_1\cr\beta_2&\alpha\endpmatrix$$
$$\begin{pmatrix} \alpha&-\beta_1\cr\beta_2&\alpha\end{pmatrix}$$
collapses an eigenvalue of $A$ to $-1$ iff the matrix
$$\pmatrix \alpha&\beta_1\cr-\beta_2&\alpha\endpmatrix$$
does.\qed
\enddemo
$$\begin{pmatrix} \alpha&\beta_1\cr-\beta_2&\alpha\end{pmatrix}$$
does.
\end{proof}
\proclaim{Lemma 2}
\begin{lemma}
\label{sylv:second-lemma}
For any $n\times n$ matrix $A$ and $\delta_1\delta_2>0$, if there is
exactly one solution of
$$\left(I_2\otimes I_n +
2\alpha\pmatrix\gamma&\delta_1\cr-\delta_2&\gamma\endpmatrix\otimes A
2\alpha\begin{pmatrix}\gamma&\delta_1\cr-\delta_2&\gamma\end{pmatrix}\otimes A
+(\alpha^2+\beta^2)
\pmatrix\gamma&\delta_1\cr-\delta_2&\gamma\endpmatrix^2\otimes A^2\right)
\pmatrix x_1\cr x_2\endpmatrix=
\pmatrix d_1\cr d_2\endpmatrix
\begin{pmatrix}\gamma&\delta_1\cr-\delta_2&\gamma\end{pmatrix}^2\otimes A^2\right)
\begin{pmatrix} x_1\cr x_2\end{pmatrix}=
\begin{pmatrix} d_1\cr d_2\end{pmatrix}
$$
it can be obtained as
$$
\align
\begin{align*}
\left(I_n+2a_1A+(a_1^2+b_1^2)A^2\right)\left(I_n+2a_2A+(a_2^2+b_2^2)A^2\right)
x_1 & =\widehat{d_1}\\
\left(I_n+2a_1A+(a_1^2+b_1^2)A^2\right)\left(I_n+2a_2A+(a_2^2+b_2^2)A^2\right)
x_2 & =\widehat{d_2}
\endalign$$
\end{align*}
where
$$
\pmatrix \widehat{d_1}\cr\widehat{d_2}\endpmatrix =
\begin{pmatrix} \widehat{d_1}\cr\widehat{d_2}\end{pmatrix} =
\left(I_2\otimes I_n +
2\alpha\pmatrix\gamma&-\delta_1\cr\delta_2&\gamma\endpmatrix\otimes A
2\alpha\begin{pmatrix}\gamma&-\delta_1\cr\delta_2&\gamma\end{pmatrix}\otimes A
+(\alpha^2+\beta^2)
\pmatrix\gamma&-\delta_1\cr\delta_2&\gamma\endpmatrix^2\otimes A^2\right)
\pmatrix d_1\cr d_2\endpmatrix
\begin{pmatrix}\gamma&-\delta_1\cr\delta_2&\gamma\end{pmatrix}^2\otimes A^2\right)
\begin{pmatrix} d_1\cr d_2\end{pmatrix}
$$
and
$$
\align
\begin{align*}
a_1 & = \alpha\gamma - \beta\delta\\
b_1 & = \alpha\delta + \gamma\beta\\
a_2 & = \alpha\gamma + \beta\delta\\
b_2 & = \alpha\delta - \gamma\beta\\
\delta & = \sqrt{\delta_1\delta_2}
\endalign$$
\endproclaim
\end{align*}
\demo{Proof}
\end{lemma}
\begin{proof}
The matrix can be written as
$$\left(I_2\otimes I_n+(\alpha+\roman i\beta)
\pmatrix\gamma&\delta_1\cr-\delta_2&\gamma\endpmatrix\otimes A\right)
\left(I_2\otimes I_n +(\alpha-\roman i\beta)
\pmatrix\gamma&\delta_1\cr-\delta_2&\gamma\endpmatrix\otimes A\right).
$$\left(I_2\otimes I_n+(\alpha+\mathrm i\beta)
\begin{pmatrix}\gamma&\delta_1\cr-\delta_2&\gamma\end{pmatrix}\otimes A\right)
\left(I_2\otimes I_n +(\alpha-\mathrm i\beta)
\begin{pmatrix}\gamma&\delta_1\cr-\delta_2&\gamma\end{pmatrix}\otimes A\right).
$$
Note that the both matrices are regular since their product is
regular. For the same reason as in the previous proof, the following
matrix is also regular
$$\left(I_2\otimes I_n+(\alpha+\roman i\beta)
\pmatrix\gamma&-\delta_1\cr\delta_2&\gamma\endpmatrix\otimes A\right)
\left(I_2\otimes I_n +(\alpha-\roman i\beta)
\pmatrix\gamma&-\delta_1\cr\delta_2&\gamma\endpmatrix\otimes A\right),
$$\left(I_2\otimes I_n+(\alpha+\mathrm i\beta)
\begin{pmatrix}\gamma&-\delta_1\cr\delta_2&\gamma\end{pmatrix}\otimes A\right)
\left(I_2\otimes I_n +(\alpha-\mathrm i\beta)
\begin{pmatrix}\gamma&-\delta_1\cr\delta_2&\gamma\end{pmatrix}\otimes A\right),
$$
and we may multiply the equation by this matrix obtaining
$\widehat{d_1}$ and $\widehat{d_2}$. Note that the four matrices
commute, that is why we can write the whole product as
$$
\align
\left(I_2\otimes I_n + (\alpha+\roman i\beta)
\pmatrix\gamma&\delta_1\cr-\delta_2&\gamma\endpmatrix\otimes A\right)\cdot
\left(I_2\otimes I_n + (\alpha+\roman i\beta)
\pmatrix\gamma&-\delta_1\cr\delta_2&\gamma\endpmatrix\otimes A\right)&\cdot\\
\left(I_2\otimes I_n + (\alpha-\roman i\beta)
\pmatrix\gamma&\delta_1\cr-\delta_2&\gamma\endpmatrix\otimes A\right)\cdot
\left(I_2\otimes I_n + (\alpha-\roman i\beta)
\pmatrix\gamma&-\delta_1\cr\delta_2&\gamma\endpmatrix\otimes A\right)&=\\
\left(I_2\otimes I_n + 2(\alpha + \roman i\beta)
\pmatrix\gamma&0\cr 0&\gamma\endpmatrix\otimes A +
(\alpha + \roman i\beta)^2
\pmatrix\gamma^2+\delta^2&0\cr 0&\gamma^2+\delta^2\endpmatrix\otimes A^2
\begin{align*}
\left(I_2\otimes I_n + (\alpha+\mathrm i\beta)
\begin{pmatrix}\gamma&\delta_1\cr-\delta_2&\gamma\end{pmatrix}\otimes A\right)\cdot
\left(I_2\otimes I_n + (\alpha+\mathrm i\beta)
\begin{pmatrix}\gamma&-\delta_1\cr\delta_2&\gamma\end{pmatrix}\otimes A\right)&\cdot\\
\left(I_2\otimes I_n + (\alpha-\mathrm i\beta)
\begin{pmatrix}\gamma&\delta_1\cr-\delta_2&\gamma\end{pmatrix}\otimes A\right)\cdot
\left(I_2\otimes I_n + (\alpha-\mathrm i\beta)
\begin{pmatrix}\gamma&-\delta_1\cr\delta_2&\gamma\end{pmatrix}\otimes A\right)&=\\
\left(I_2\otimes I_n + 2(\alpha + \mathrm i\beta)
\begin{pmatrix}\gamma&0\cr 0&\gamma\end{pmatrix}\otimes A +
(\alpha + \mathrm i\beta)^2
\begin{pmatrix}\gamma^2+\delta^2&0\cr 0&\gamma^2+\delta^2\end{pmatrix}\otimes A^2
\right)&\cdot\\
\left(I_2\otimes I_n + 2(\alpha - \roman i\beta)
\pmatrix\gamma&0\cr 0&\gamma\endpmatrix\otimes A +
(\alpha - \roman i\beta)^2
\pmatrix\gamma^2+\delta^2&0\cr 0&\gamma^2+\delta^2\endpmatrix\otimes A^2
\left(I_2\otimes I_n + 2(\alpha - \mathrm i\beta)
\begin{pmatrix}\gamma&0\cr 0&\gamma\end{pmatrix}\otimes A +
(\alpha - \mathrm i\beta)^2
\begin{pmatrix}\gamma^2+\delta^2&0\cr 0&\gamma^2+\delta^2\end{pmatrix}\otimes A^2
\right)&
\endalign
$$
\end{align*}
The product is a diagonal consiting of two $n\times n$ blocks, which are the
same. The block can be rewritten as product:
$$
\align
(I_n+(\alpha+\roman i\beta)(\gamma+\roman i\delta)A)\cdot
(I_n+(\alpha+\roman i\beta)(\gamma-\roman i\delta)A)&\cdot\\
(I_n+(\alpha-\roman i\beta)(\gamma+\roman i\delta)A)\cdot
(I_n+(\alpha-\roman i\beta)(\gamma-\roman i\delta)A)&
\endalign
$$
\begin{align*}
(I_n+(\alpha+\mathrm i\beta)(\gamma+\mathrm i\delta)A)\cdot
(I_n+(\alpha+\mathrm i\beta)(\gamma-\mathrm i\delta)A)&\cdot\\
(I_n+(\alpha-\mathrm i\beta)(\gamma+\mathrm i\delta)A)\cdot
(I_n+(\alpha-\mathrm i\beta)(\gamma-\mathrm i\delta)A)&
\end{align*}
and after reordering
$$
\align
(I_n+(\alpha+\roman i\beta)(\gamma+\roman i\delta)A)\cdot
(I_n+(\alpha-\roman i\beta)(\gamma-\roman i\delta)A)&\cdot\\
(I_n+(\alpha+\roman i\beta)(\gamma-\roman i\delta)A)\cdot
(I_n+(\alpha-\roman i\beta)(\gamma+\roman i\delta)A)&=\\
\begin{align*}
(I_n+(\alpha+\mathrm i\beta)(\gamma+\mathrm i\delta)A)\cdot
(I_n+(\alpha-\mathrm i\beta)(\gamma-\mathrm i\delta)A)&\cdot\\
(I_n+(\alpha+\mathrm i\beta)(\gamma-\mathrm i\delta)A)\cdot
(I_n+(\alpha-\mathrm i\beta)(\gamma+\mathrm i\delta)A)&=\\
(I_n+2(\alpha\gamma-\beta\delta)A+
(\alpha^2+\beta^2)(\gamma^2+\delta^2)A^2)&\cdot\\
(I_n+2(\alpha\gamma+\beta\delta)A+
(\alpha^2+\beta^2)(\gamma^2+\delta^2)A^2)&
\endalign
$$
\end{align*}
Now it suffices to compare $a_1=\alpha\gamma-\beta\delta$ and verify
that
$$
\align
\begin{align*}
b_1^2 & = (\alpha^2+\beta^2)(\gamma^2+\delta^2)-a_1^2 =\cr
& = \alpha^2\gamma^2+\beta^2\gamma^2+\alpha^2\beta^2+\beta^2\delta^2-
(\alpha\gamma)^2+2\alpha\beta\gamma\delta-(\beta\delta)^2=\cr
& = (\beta\gamma)^2 + (\alpha\beta)^2 + 2\alpha\beta\gamma\delta=\cr
& = (\beta\gamma +\alpha\beta)^2
\endalign
$$
\end{align*}
For $b_2$ it is done in the same way.
\qed
\enddemo
\end{proof}
\head The Algorithm\endhead
\section{The Algorithm}
Below we define three functions of which
$\vec(Y)=\solvi(1,\vec(\widehat{D}),i)$ provides the solution $Y$. $X$
is then obtained as $X=U^TY\left(\otimesi V\right)$.
\subhead Synopsis\endsubhead
\subsection{Synopsis}
$F^T$ is $m\times m$ lower quasi-triangular matrix. Let $m_r$ be a
number of real eigenvalues, $m_c$ number of complex pairs. Thus
@ -215,7 +217,7 @@ vectors of appropriate dimensions, and $x_{\bar j}$ is $\bar j$-th
partition of $x$, and $x_j=(x_{\bar j}\quad x_{\bar j+1})^T$ if $j$-th
eigenvalue is complex, and $x_j=x_{\bar j}$ if $j$-th eigenvalue is real.
\subhead Function $\solvi$\endsubhead
\subsection{Function $\solvi$}
The function $x=\solvi(r,d,i)$ solves equation
$$\left(I_{m^i}\otimes I_n+r\iF\otimes K\right)x = d.$$
@ -226,7 +228,7 @@ quasi-triangular matrix, so this is easy.
If $i>0$, then we go through diagonal blocks $F_j$ for
$j=1,\ldots, m_r+m_c$ and perform:
\roster
\begin{enumerate}
\item if $F_j=(f_{\bar j\bar j}) = (f)$, then we return
$x_j=\solvi(rf,d_{\bar j}, i-1)$. Then precalculate $y=d_j-x_j$, and
eliminate guys below $F_j$. This is, for each $k=\bar j+1,\ldots, m$, we
@ -234,46 +236,45 @@ put
$$d_k = d_k-rf_{\bar jk}\left(\imF\otimes K\right)x_{\bar j}=
d_k - \frac{f_{\bar jk}}{f}y$$
\item if $F_j=\pmatrix\alpha&\beta_1\cr -\beta_2&\alpha\endpmatrix$,
\item if $F_j=\begin{pmatrix}\alpha&\beta_1\cr -\beta_2&\alpha\end{pmatrix}$,
we return $x_j=\solvii(r\alpha, r\beta_1, r\beta_2, d_j, i-1)$. Then
we precalculate
$$y=\left(\pmatrix\alpha&-\beta_1\cr \beta_2&\alpha\endpmatrix
$$y=\left(\begin{pmatrix}\alpha&-\beta_1\cr \beta_2&\alpha\end{pmatrix}
\otimes I_{m^{i-1}}\otimes I_n\right)
\pmatrix d_{\bar j} - x_{\bar j}\cr
\begin{pmatrix} d_{\bar j} - x_{\bar j}\cr
d_{\bar j+1} - x_{\bar j+1}
\endpmatrix$$
\end{pmatrix}$$
and eliminate guys below $F_j$. This is, for each $k=\bar j+2,\ldots, n$
we put
$$
\align
\begin{align*}
d_k &= d_k - r(f_{{\bar j}k}\quad f_{{\bar j}+1 k})
\otimes\left(\imF\otimes K\right)x_j\\
&= d_k - \frac{1}{\alpha^2+\beta_1\beta_2}
\left((f_{{\bar j}k}\quad f_{{\bar j}+1 k})
\otimes I_{m^{i-1}}\otimes I_n\right)y
\endalign
$$
\endroster
\end{align*}
\subhead Function $\solvii$\endsubhead
\end{enumerate}
\subsection{Function $\solvii$}
The function $x=\solvii(\alpha, \beta_1, \beta_2, d, i)$ solves
equation
$$
\left(I_2\otimes I_{m^i}\otimes I_n +
\pmatrix\alpha&\beta_1\cr-\beta_2&\alpha\endpmatrix
\begin{pmatrix}\alpha&\beta_1\cr-\beta_2&\alpha\end{pmatrix}
\otimes\iF\otimes K\right)x=d
$$
According to {\bf Lemma 1} the function returns
According to Lemma \ref{sylv:first-lemma} the function returns
$$
x=\pmatrix\solviip(\alpha,\beta_1\beta_2,\widehat{d_1},i)\cr
\solviip(\alpha,\beta_1\beta_2,\widehat{d_2},i)\endpmatrix,
x=\begin{pmatrix}\solviip(\alpha,\beta_1\beta_2,\widehat{d_1},i)\cr
\solviip(\alpha,\beta_1\beta_2,\widehat{d_2},i)\end{pmatrix},
$$
where $\widehat{d_1}$, and $\widehat{d_2}$ are partitions of
$\widehat{d}$ from the lemma.
\subhead Function $\solviip$\endsubhead
\subsection{Function $\solviip$}
The function $x=\solviip(\alpha,\beta^2,d,i)$ solves equation
$$
@ -291,7 +292,7 @@ then it is lower triangular.
If $i>0$, then we go through diagonal blocks $F_j$ for $j=1,\ldots, m_r+m_c$
and perform:
\roster
\begin{enumerate}
\item if $F_j=(f_{\bar j\bar j})=(f)$ then $j$-th diagonal block of
$$
I_{m^i}\otimes I_n + 2\alpha\iF\otimes K +
@ -311,16 +312,14 @@ $$y_1 = 2\alpha f(\imF\otimes K)x_j = d_j-x_j-y_2.$$
Let $g_{pq}$ denote element of $F^{2T}$ at position $(q,p)$.
The elimination is done by going through $k=\bar j+1,\ldots, m$ and
putting
$$
\align
\begin{align*}
d_k &= d_k - \left(2\alpha f_{\bar j k}\imF\otimes K +
(\alpha^2+\beta^2)g_{\bar j k}\imF^2\otimes K^2\right)x_j\\
&= d_k - \frac{f_{\bar j k}}{f}y_1 -
\frac{g_{\bar j k}}{f^2}y_2
\endalign
$$
\end{align*}
\item if $F_j=\pmatrix\gamma&\delta_1\cr -\delta_2&\gamma\endpmatrix$,
\item if $F_j=\begin{pmatrix}\gamma&\delta_1\cr -\delta_2&\gamma\end{pmatrix}$,
then $j$-th diagonal block of
$$
I_{m^i}\otimes I_n + 2\alpha\iF\otimes K +
@ -329,26 +328,24 @@ $$
takes the form
$$
I_{m^{i-1}}\otimes I_n +2\alpha
\pmatrix\gamma&\delta_1\cr -\delta_2&\gamma\endpmatrix\imF\otimes K
\begin{pmatrix}\gamma&\delta_1\cr -\delta_2&\gamma\end{pmatrix}\imF\otimes K
+(\alpha^2+\beta^2)
\pmatrix\gamma&\delta_1\cr -\delta_2&\gamma\endpmatrix^2\imF^2\otimes K^2
\begin{pmatrix}\gamma&\delta_1\cr -\delta_2&\gamma\end{pmatrix}^2\imF^2\otimes K^2
$$
According to {\bf Lemma 2}, we need to calculate
According to Lemma \ref{sylv:second-lemma}, we need to calculate
$\widehat{d}_{\bar j}$, and $\widehat{d}_{\bar j+1}$, and $a_1$,
$b_1$, $a_2$, $b_2$. Then we obtain
$$
\align
\begin{align*}
x_{\bar j}&=
\solviip(a_1,b_1^2,\solviip(a_2,b_2^2,\widehat{d}_{\bar j},i-1),i-1)\\
x_{\bar j+1}&=
\solviip(a_1,b_1^2,\solviip(a_2,b_2^2,\widehat{d}_{\bar j+1},i-1),i-1)
\endalign
$$
\end{align*}
Now we need to eliminate guys below $F_j$. Since $\Vert F^2_j\Vert <
\Vert F_j\Vert$, we precalculate
$$
\align
\begin{align*}
y_2&=(\alpha^2+\beta^2)(\gamma^2+\delta^2)
\left(I_2\otimes\imF^2\otimes K^2\right)x_j\\
y_1&=2\alpha(\gamma^2+\delta^2)\left(I_2\otimes\imF\otimes
@ -360,37 +357,36 @@ K\right)x_j\\
\left(
F_j^2
\otimes I_{m^{i-1}n}\right)y_2\right)\\
&=\left(\pmatrix\gamma&-\delta_1\cr\delta_2&\gamma\endpmatrix
&=\left(\begin{pmatrix}\gamma&-\delta_1\cr\delta_2&\gamma\end{pmatrix}
\otimes I_{m^{i-1}n}\right)(d_j-x_j)
-\left(\pmatrix\gamma&\delta_1\cr-\delta_2&\gamma\endpmatrix
-\left(\begin{pmatrix}\gamma&\delta_1\cr-\delta_2&\gamma\end{pmatrix}
\otimes I_{m^{i-1}n}\right)y_2
\endalign
$$
\end{align*}
Then we go through all $k=\bar j+2,\ldots, m$. For clearer formulas, let
$\bold f_k$ denote pair of $F^T$ elements in $k$-th line below $F_j$,
this is $\bold f_k=(f_{\bar jk}\quad f_{\bar j+1k})$. And let $\bold g_k$
denote the same for $F^{2T}$, this is $\bold g_k=(g_{\bar jk}\quad
$\mathbf f_k$ denote pair of $F^T$ elements in $k$-th line below $F_j$,
this is $\mathbf f_k=(f_{\bar jk}\quad f_{\bar j+1k})$. And let $\mathbf g_k$
denote the same for $F^{2T}$, this is $\mathbf g_k=(g_{\bar jk}\quad
g_{\bar j+1k})$. For each $k$ we put
$$
\align
d_k &= d_k - \left(2\alpha\bold f_k\otimes
\begin{align*}
d_k &= d_k - \left(2\alpha\mathbf f_k\otimes
\imF\otimes K +
(\alpha^2+\beta^2)\bold g_k\otimes
(\alpha^2+\beta^2)\mathbf g_k\otimes
\imF^2\otimes K^2\right)x_j\\
&= d_k - \frac{1}{\gamma^2+\delta^2}
\left(\bold f_k\otimes
\left(\mathbf f_k\otimes
I_{m^{i-1}n}\right)y_1
- \frac{1}{\gamma^2+\delta^2}
\left(\bold g_k\otimes
\left(\mathbf g_k\otimes
I_{m^{i-1}n}\right)y_2
\endalign
$$
\end{align*}
\endroster
\end{enumerate}
\head Final Notes\endhead
\section{Final Notes}
\subhead Numerical Issues of $A^{-1}B$\endsubhead
\subsection{Numerical Issues of $A^{-1}B$}
We began the solution of the Sylvester equation with multiplication by
$A^{-1}$. This can introduce numerical errors, and we need more
@ -448,7 +444,7 @@ We try to solve $M\vec(X) = T_n(0) = 0$. Since $M$ is
skew symmetric, there is real orthonormal matrix $Q$, such that
$M=Q\widehat{M}Q^T$, and $\widehat{M}$ is block diagonal matrix
consisting of $2\times 2$ blocks of the form
$$\left(\matrix 0&\alpha_i\cr-\alpha_i&0\endmatrix\right),$$
$$\left(\begin{matrix} 0&\alpha_i\cr-\alpha_i&0\end{matrix}\right),$$
and of additional zero, if $n^2$ is odd.
Now we solve equation $\widehat{M}y=0$, where $y=Q^T\vec(X)$. Now
@ -462,7 +458,7 @@ structural zeros, a solution is obtained by picking arbitrary numbers
for the same positions in $y$, and put $\vec(X)=Qy$.
The following questions need to be answered:
\roster
\begin{enumerate}
\item How to recognize the structural rows?
\item Is $A^{-1}$ generated by a $y$, which has non-zero elements only
on structural rows? Note that $A$ can have repetitive eigenvalues. The
@ -471,9 +467,9 @@ $y$ there is exactly one structural row.
\item And very difficult one: How to pick $y$ so that $X$ would be
regular, or even close to orthonormal (pure orthonormality
overdeterminates $y$)?
\endroster
\end{enumerate}
\subhead Making Zeros in $F$\endsubhead
\subsection{Making Zeros in $F$}
It is clear that the numerical complexity of the proposed algorithm
strongly depends on a number of non-zero elements in the Schur factor
@ -482,10 +478,10 @@ substantially less zeros than $F$, then the computation would be
substantially faster. However, it seems that we have to pay price for
any additional zero in terms of less numerical stability of $PFP^{-1}$
multiplication. Consider $P$, and $F$ in form
$$P=\pmatrix I &X\cr 0&I\endpmatrix,
\qquad F=\pmatrix A&C\cr 0&B\endpmatrix$$
$$P=\begin{pmatrix} I &X\cr 0&I\end{pmatrix},
\qquad F=\begin{pmatrix} A&C\cr 0&B\end{pmatrix}$$
we obtain
$$PFP^{-1}=\pmatrix A& C + XB - AX\cr 0&B \endpmatrix$$
$$PFP^{-1}=\begin{pmatrix} A& C + XB - AX\cr 0&B \end{pmatrix}$$
Thus, we need to solve $C = AX - XB$. Its clear that numerical
stability of operator $Y\mapsto PYP^{-1}$ and its inverse $Y\mapsto
@ -503,7 +499,7 @@ partitioning is not possible without breaking some user given limit
for numerical errors. We have to keep in mind that the numerical
errors are accumulated in product of all $P$'s of every step.
\subhead Exploiting constant rows in $F$\endsubhead
\subsection{Exploiting constant rows in $F$}
If some of $F$'s rows consists of the same numbers, or a number of
distict values within a row is small, then this structure can be
@ -529,13 +525,12 @@ in order to minimize $\Vert X\Vert$ if $A$, and $B$ are given. Now, in
the next step we need to introduce zeros (or constant rows) to matrix
$A$, so we seek for regular matrix $P$, doing the
job. If found, the product looks like:
$$\pmatrix P&0\cr 0&I\endpmatrix\pmatrix A&R\cr 0&B\endpmatrix
\pmatrix P^{-1}&0\cr 0&I\endpmatrix=
\pmatrix PAP^{-1}&PR\cr 0&B\endpmatrix$$
$$\begin{pmatrix} P&0\cr 0&I\end{pmatrix}\begin{pmatrix} A&R\cr 0&B\end{pmatrix}
\begin{pmatrix} P^{-1}&0\cr 0&I\end{pmatrix}=
\begin{pmatrix} PAP^{-1}&PR\cr 0&B\end{pmatrix}$$
Now note, that matrix $PR$ has also constant rows. Thus,
preconditioning of the matrix in upper left corner doesn't affect the
property. However, a preconditioning of the matrix in lower right
corner breaks the property, since we would obtain $RP^{-1}$.
\enddocument
\end{document}

246
dynare++/doc/tl.tex Normal file
View File

@ -0,0 +1,246 @@
\documentclass[11pt,a4paper]{article}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{fullpage}
\begin{document}
\author{Ondra Kamenik}
\title{Multidimensional Tensor Library \\ for perturbation methods applied to DSGE
models}
\date{2004}
\maketitle
\section{Introduction}
The design of the library was driven by the needs of perturbation
methods for solving Stochastic Dynamic General Equilibrium models. The
aim of the library is not to provide an exhaustive interface to
multidimensional linear algebra. The tensor library's main purposes
include:
\begin{itemize}
\item Define types for tensors, for a multidimensional index of a
tensor, and types for folded and unfolded tensors. The tensors defined
here have only one multidimensional index and one reserved
one-dimensional index. The tensors should allow modelling of higher
order derivatives with respect to a few vectors with different sizes
(for example $\left[g_{y^2u^3}\right]$). The tensors should allow
folded and unfolded storage modes and conversion between them. A
folded tensor stores symmetric elements only once, while an unfolded
stores data as a whole multidimensional cube.
\item Define both sparse and dense tensors. We need only one particular
type of sparse tensor. This in contrast to dense tensors, where we
need much wider family of types.
\item Implement the Faa Di Bruno multidimensional formula. So, the main
purpose of the library is to implement the following step of Faa Di Bruno:
$$\left[B_{s^k}\right]_{\alpha_1\ldots\alpha_k}
=\left[h_{y^l}\right]_{\gamma_1\ldots\gamma_l}
\left(\sum_{c\in M_{l,k}}
\prod_{m=1}^l\left[g_{s^{\vert c_m\vert}}\right]^{\gamma_m}_{c_m(\alpha)}\right)$$
where $s$ can be a compound vector of variables, where $h_{y^l}$ and $g_{s^i}$
are tensors, $M_{l,k}$ is a set of
all equivalences of $k$ element set having $l$ classes, $c_m$ is
$m$-th class of equivalence $c$, $\vert c_m\vert$ is its
cardinality, and $c_m(\alpha)$ is a tuple of
picked indices from $\alpha$ by class $c_m$.
Note that the sparse tensors play a role of $h$ in the Faa Di Bruno, not
of $B$ nor $g$.
\end{itemize}
\section{Classes}
The following list is a road-map to various classes in the library.
\begin{description}
\item[Tensor]
Virtual base class for all dense tensors, defines \emph{index} as the
multidimensonal iterator
\item[FTensor]
Virtual base class for all folded tensors
\item[UTensor]
Virtual base class for all unfolded tensors
\item[FFSTensor]
Class representing folded full symmetry dense tensor,
for instance $\left[g_{y^3}\right]$
\item[FGSTensor]
Class representing folded general symmetry dense tensor,
for instance $\left[g_{y^2u^3}\right]$
\item[UFSTensor]
Class representing unfolded full symmetry dense tensor,
for instance $\left[g_{y^3}\right]$
\item[UGSTensor]
Class representing unfolded general symmetry dense tensor,
for instance $\left[g_{y^2u^3}\right]$
\item[URTensor]
Class representing unfolded/folded full symmetry, row-oriented,
dense tensor. Row-oriented tensors are used in the Faa Di Bruno
above as some part (few or one column) of a product of $g$'s. Their
fold/unfold conversions are special in such a way, that they must
yield equivalent results if multiplied with folded/unfolded
column-oriented counterparts.
\item[URSingleTensor]
Class representing unfolded/folded full symmetry, row-oriented,
single column, dense tensor. Besides use in the Faa Di Bruno, the
single column row oriented tensor models also higher moments of normal
distribution.
\item[UPSTensor]
Class representing unfolded, column-oriented tensor whose symmetry
is not that of the $\left[B_{y^2u^3}\right]$ but rather of something
as $\left[B_{yuuyu}\right]$. This tensor evolves during the product
operation for unfolded tensors and its basic operation is to add
itself to a tensor with nicer symmetry, here $\left[B_{y^2u^3}\right]$.
\item[FPSTensor]
Class representing partially folded, column-oriented tensor whose
symmetry is not that of the $\left[B_{y^3u^4}\right]$ but rather
something as $\left[B_{yu\vert y^3u\vert u^4}\right]$, where the
portions of symmetries represent folded dimensions which are combined
in unfolded manner. This tensor evolves during the Faa Di Bruno
for folded tensors and its basic operation is to add itself to a
tensor with nicer symmetry, here folded $\left[B_{y^3u^4}\right]$.
\item[USubTensor]
Class representing unfolded full symmetry, row-oriented tensor which
contains a few columns of huge product
$\prod_{m=1}^l\left[g_{s^{\vert c_m\vert}}\right]^{\gamma_m}_{c_m(\alpha)}$. This is
needed during the Faa Di Bruno for folded matrices.
\item[IrregTensor]
Class representing a product of columns of derivatives
$\left[z_{y^ku^l}\right]$, where $z=[y^T,v^T,w^T]^T$. Since the first
part of $z$ is $y$, the derivatives contain many zeros, which are not
stored, hence the tensor's irregularity. The tensor is used when
calculating one step of Faa Di Bruno formula, i.e.
$\left[h_{y^l}\right]_{\gamma_1\ldots\gamma_l}
\left(\sum_{c\in M_{l,k}}
\prod_{m=1}^l\left[g_{s^{\vert c_m\vert}}\right]^{\gamma_m}_{c_m(\alpha)}\right)$.
\item[FSSparseTensor]
Class representing full symmetry, column-oriented, sparse tensor. It
is able to store elements keyed by the multidimensional index, and
multiply itself with one column of row-oriented tensor.
\item[FGSContainer]
Container of \texttt{FGSTensor}s. It implements the Faa Di Bruno with
unfolded or folded tensor $h$ yielding folded $B$. The methods are
\texttt{FGSContainer::multAndAdd}.
\item[UGSContainer]
Container of \texttt{UGSTensor}s. It implements the Faa Di Bruno with
unfolded tensor $h$ yielding unfolded $B$. The method is
\texttt{UGSContainer::multAndAdd}.
\item[StackContainerInterface]
Virtual pure interface describing all logic
of stacked containers for which we will do the Faa Di Bruno operation.
\item[UnfoldedStackContainer]
Implements the Faa Di Bruno operation for stack of
containers of unfolded tensors.
\item[FoldedStackContainer]
Implements the Faa Di Bruno for stack of
containers of folded tensors.
\item[ZContainer]
The class implements the interface \texttt{StackContainerInterface} according
to $z$ appearing in context of DSGE models. By a simple inheritance,
we obtain \texttt{UnfoldedZContainer} and also \texttt{FoldedZContainer}.
\item[GContainer]
The class implements the interface \texttt{StackContainerInterface} according
to $G$ appearing in context of DSGE models. By a simple inheritance,
we obtain \texttt{UnfoldedGContainer} and also \texttt{FoldedGContainer}.
\item[Equivalence]
The class represents an equivalence on $n$-element set. Useful in the
Faa Di Bruno.
\item[EquivalenceSet]
The class representing all equivalences on $n$-element set. Useful in the
Faa Di Bruno.
\item[Symmetry]
The class defines a symmetry of general symmetry tensor. This is it
defines a basic shape of the tensor. For $\left[B_{y^2u^3}\right]$,
the symmetry is $y^2u^3$.
\item[Permutation]
The class represents a permutation of $n$ indices. Useful in the
Faa Di Bruno.
\item[IntSequence]
The class represents a sequence of integers. Useful everywhere.
\item[TwoDMatrix and ConstTwoDMatrix]
These classes provide an interface to a code handling two-dimensional
matrices. The code resides in Sylvester module, in directory {\tt
sylv/cc}. There is
no similar interface to \texttt{Vector} and \texttt{ConstVector} classes from the
Sylvester module and they are used directly.
\item[KronProdAll]
The class represents a Kronecker product of a sequence of arbitrary
matrices and is able to multiply a matrix from the right without
storing the Kronecker product in memory.
\item[KronProdAllOptim]
The same as \texttt{KronProdAll} but it optimizes the order of matrices in
the product to minimize the used memory during the Faa Di Bruno
operation. Note that it is close to optimal flops.
\item[FTensorPolynomial and UTensorPolynomial]
Abstractions representing a polynomial whose coefficients are
folded/unfolded tensors and variable is a column vector. The classes
provide methods for traditional and horner-like polynomial
evaluation. This is useful in simulation code.
\item[FNormalMoments and UNormalMoments]
These are containers for folded/unfolded single column tensors for
higher moments of normal distribution. The code contains an algorithm
for generating the moments for arbitrary covariance matrix.
\item[TLStatic]
The class encapsulates all static information needed for the
library. It includes precalculated equivalence sets.
\item[TLException]
Simple class thrown as an exception.
\end{description}
\section{Multi-threading}
The tensor library is multi-threaded. The basic property of the
thread implementation in the library is that we do not allow running
more concurrent threads than the preset limit. This prevents threads
from competing for memory in such a way that the OS constantly switches
among threads with frequent I/O for swaps. This may occur since one
thread might need much own memory. The threading support allows for
detached threads, the synchronization points during the Faa Di Bruno
operation are relatively short, so the resulting load is close to the
preset maximum number parallel threads.
\section{Tests}
A few words to the library's test suite. The suite resides in
directory {\tt tl/testing}. There is a file {\tt tests.cc} which
contains all tests and {\tt main()} function. Also there are files
{\tt factory.hh} and {\tt factory.cc} implementing random generation
of various objects. The important property of these random objects is
that they are the same for all object's invocations. This is very
important in testing and debugging. Further, one can find files {\tt
monoms.hh} and {\tt monoms.cc}. See below for their explanation.
There are a few types of tests:
\begin{itemize}
\item We test for tensor indices. We go through various tensors with
various symmetries, convert indices from folded to unfolded and
vice-versa. We test whether their coordinates are as expected.
\item We test the Faa Di Bruno by comparison of the results of
\texttt{FGSContainer::multAndAdd} against the results of \texttt{UGSContainer::multAndAdd}. The two
implementations are pretty different, so this is a good test.
\item We use a code in {\tt monoms.hh} and {\tt monoms.cc} to generate a
random vector function $f(x(y,u))$ along with derivatives of
$\left[f_x\right]$, $\left[x_{y^ku^l}\right]$, and
$\left[f_{y^ku^l}\right]$. Then we calculate the resulting derivatives
$\left[f_{y^ku^l}\right]$ using \texttt{multAndAdd} method of \texttt{UGSContainer}
or \texttt{FGSContainer} and compare the derivatives provided by {\tt
monoms}. The functions generated in {\tt monoms} are monomials with
integer exponents, so the implementation of {\tt monoms} is quite
easy.
\item We do a similar thing for sparse tensors. In this case the {\tt monoms}
generate a function $f(y,v(y,u),w(y,u))$, provide all the derivatives
and the result $\left[f_{y^ku^l}\right]$. Then we calculate the
derivatives with \texttt{multAndAdd} of \texttt{ZContainer} and compare.
\item We test the polynomial evaluation by evaluating a folded and
unfolded polynomial in traditional and Horner-like fashion. This gives
four methods in total. The four results are compared.
\end{itemize}
\end{document}

View File

@ -1,54 +0,0 @@
RINTERNALS=/usr/share/R/include/
sylvcppsource := $(wildcard ../../sylv/cc/*.cpp)
sylvhsource := $(wildcard ../../sylv/cc/*.h)
sylvobjects := $(patsubst %.cpp, %.o, $(sylvcppsource))
tlcwebsource := $(wildcard ../../tl/cc/*.cweb)
tlcppsource := $(patsubst %.cweb,%.cpp,$(tlcwebsource))
tlhwebsource := $(wildcard ../../tl/cc/*.hweb)
tlhsource := $(patsubst %.hweb,%.h,$(tlhwebsource))
tlobjects := $(patsubst %.cweb,%.o,$(tlcwebsource))
kordcwebsource := $(wildcard ../../kord/*.cweb)
kordcppsource := $(patsubst %.cweb,%.cpp,$(kordcwebsource))
kordhwebsource := $(wildcard ../../kord/*.hweb)
kordhsource := $(patsubst %.hweb,%.h,$(kordhwebsource))
kordobjects := $(patsubst %.cweb,%.o,$(kordcwebsource))
integcwebsource := $(wildcard ../../integ/cc/*.cweb)
integcppsource := $(patsubst %.cweb,%.cpp,$(integcwebsource))
integhwebsource := $(wildcard ../../integ/cc/*.hweb)
integhsource := $(patsubst %.hweb,%.h,$(integhwebsource))
integobjects := $(patsubst %.cweb,%.o,$(integcwebsource))
parserhsource := $(wildcard ../../parser/cc/*.h)
parsercppsource := $(wildcard ../parser/cc/*.cpp)
utilshsource := $(wildcard ../../utils/cc/*.h)
utilscppsource := $(wildcard ../utils/cc/*.cpp)
srccpp := dynare3.cpp dynare_model.cpp planner_builder.cpp dynare_atoms.cpp dynare_params.cpp nlsolve.cpp
objects := $(patsubst %.cpp,../../src/%.o,$(srccpp)) \
$(patsubst %.y,%_ll.o,$(wildcard ../../src/*.y)) \
$(patsubst %.lex,%_tab.o,$(wildcard ../../src/*.lex))
PKG_CPPFLAGS= -I../../tl/cc -I../../sylv/cc -I../../kord -I../../src -I../.. -I$(RINTERNALS)
PKG_LIBS= ${LAPACK_LIBS} ${BLAS_LIBS} $(objects) $(kordobjects) $(integobjects) $(tlobjects) ../../parser/cc/parser.a ../../utils/cc/utils.a $(sylvobjects) -lpthread -llapack -lcblas -lf77blas -latlas -lg2c -lstdc++
ifneq ($(LD_LIBRARY_PATH),) # use LD_LIBRARY_PATH from environment
PKG_LIBS := -Wl,--library-path $(LD_LIBRARY_PATH) $(PKG_LIBS)
endif
dynareR.so: dynareR.o
g++ -shared -o dynareR.so dynareR.o -L/usr/lib/R/lib -lR $(PKG_LIBS)
dynareR.o: dynareR.cpp
g++ -I/usr/share/R/include -I/usr/share/R/include $(PKG_CPPFLAGS) \
-fpic -g -O2 -c dynareR.cpp -o dynareR.o -DDEBUG
test: test.cpp dynareR.cpp
g++ -O0 -g -o test test.cpp -DDEBUG $(PKG_LIBS) $(PKG_CPPFLAGS)
test-debug:
valgrind --leak-check=yes ./test

View File

@ -1,17 +0,0 @@
COMPILING
The makefile for this interface is still preliminary, I will write a decent
one when I have the time. It needs all the compiled files from dynare++,
but doesn't know how to make them. So first you need to run make in the
src/ directory, then run make in extern/R.
You need Rinternals.h to make this file. If you are not using prepackaged R
on Unix/Linux, you need to modify the variable RINCLUDE in the Makefile
accordingly.
To compile dynare++, read doc/compiling-notes.txt.
INSTALLATION
Copy the dynareR.r and dynareR.so files to your working directory so that R
can find them.

View File

@ -1,249 +0,0 @@
// $Id: dynareR.cpp 862 2006-08-04 17:34:56Z tamas $
// Copyright 2006, Tamas K Papp
#include "dynare3.h" // Dynare class
#include "approximation.h" // Approximation class
// exceptions
#include "dynare_exception.h"
#include "parser/cc/parser_exception.h"
#include "utils/cc/exception.h"
#include "SylvException.h"
#include "tl_exception.h"
#include "kord_exception.h"
#include <algorithm>
#include <string.h>
#ifdef DEBUG
#include <stdio.h>
#endif
#include <R_ext/Memory.h>
/** This file containt the C glue functions for an R interface to
* Dynare++. Although written in standard C (except for the use of
* R_alloc), the indexing, calling and memory management conventions
* of the functions in this file were tailored for R.
*
* It is not recommended that you use this interface for anything else
* but R.
*/
/** Error codes: these error codes correspond to possible
* exceptions. */
#define DYNARER_SYLVEXCEPTION 1
#define DYNARER_DYNAREEXCEPTION 2
#define DYNARER_OGUEXCEPTION 3
#define DYNARER_TLEXCEPTION 4
#define DYNARER_KORDEXCEPTION 5
#define DYNARER_NAMESMATCHINGERROR 6
/** Copies the message into a buffer. The buffer is allocated and
* managed by R, ie it will be garbage collected after the .C call
* returns and the contents are duplicated.
*/
char *passmessage(const char *errormessage) {
long l = strlen(errormessage);
char *em = R_alloc(l, 1);
return strcpy(em, errormessage);
}
/** This function puts the mapping between the newtotal items after
* nl[offset] and the items in orig into the buffer perm, which has to
* be at least as long as newtotal. The function uses R indexing,
* that is to say, the first index is 1.
*/
int matchnames(const char **orig, int origtotal,
const NameList &nl, int offset, int newtotal,
int *perm) {
#ifdef DEBUG
printf("matching names (R indexing):\n");
#endif
for (int i=0; i < newtotal; i++) {
int j;
for (j=0; j < origtotal; j++)
if (strcmp(nl.getName(offset+i), *(orig+j))==0) {
*(perm+i) = j+1;
#ifdef DEBUG
printf("%d -> %d\n",i+1,j+1);
#endif
break;
}
if (j==origtotal)
return 1;
}
return 0;
}
/** dynareR is the interface function. The user provides:
* - a list of endogenous and exogenous variables, a list of
* parameters (and the length of each list)
* - the model equations (modeleq, pointer to a 0-terminated string)
* - the order of expansion (ord)
* - journal file name (jnlfile, can be "/dev/null" for no journal)
* - values for the parametes (parval)
* - variance-covariance matrix (vcov, stacked by columns, R does
* this)
* - initial values for finding the steady state (initval)
* - and the number of steps for the approximation algorithm
* (numsteps)
*
* If successful, the interface will write the results to these
* buffers:
* - tensorbuffer for the steady state and the flattened tensors
* - num_state for the number of endogenous variables that ended up in
* the state
* - mappings to variable names (ordering_state, ordering_endo,
* ordering_exo), indices start from 1
* - the deterministic steady state (newinitval)
*
* If dynare throws an exception, the interface tries to catch it and
* return an error code (error), and error message (errormessage), and
* if applicable, information on the stability of the model
* (kordcode). errormessage is allocated into R's memory, and will be
* collected after duplication.
*/
extern "C" {
void dynareR(const char** endo, const int* num_endo,
const char** exo, const int* num_exo,
const char** par, const int* num_par,
const char** equations, const int* ord, const char* jnlfile,
const double *parval, const double *vcov,
const double *initval,
const int *num_steps,
double* tensorbuffer,
int *num_state, int *ordering_state,
int *ordering_endo, int *ordering_exo,
double *newinitval,
int* error, char **errormessage, int *kordcode) {
// construct the model here
try {
#ifdef DEBUG // will print only first var names etc.
printf("eq: %s\nendo: %d %s\nexo: %d %s\npar: %d %s\nord: %d\n",
*equations,*num_endo,*endo,*num_exo,*exo,*num_par,*par,*ord);
#endif
// create journal
Journal journal(jnlfile);
// create Dynare object
Dynare dynare(endo, *num_endo, exo, *num_exo,
par, *num_par, *equations, strlen(*equations),
*ord, journal);
// set Vcov and parameter values
copy(parval,parval+(*num_par),dynare.getParams().base());
#ifdef DEBUG
printf("parameter values (%d):\n",dynare.getParams().length());
dynare.getParams().print();
#endif
copy(vcov,vcov+(*num_exo)*(*num_exo),dynare.getVcov().base());
#ifdef DEBUG
printf("vcov matrix:\n");
dynare.getVcov().print();
#endif
// set initial values
Vector iv(initval,*num_endo);
#ifdef DEBUG
printf("initial values:\n");
iv.print();
#endif
dynare.setInitOuter(iv);
// construct approximation
tls.init(dynare.order(),
dynare.nstat()+2*dynare.npred()+3*dynare.nboth()+
2*dynare.nforw()+dynare.nexog());
Approximation approximation(dynare,journal,*num_steps);
approximation.walkStochSteady();
// write the steady state into the buffer
int ny = dynare.ny();
const Vector ss(dynare.getSteady());
// ss = ConstVector(approximation.getSS(), 0); // FIXME allow
// // for nonzero
int s = dynare.getStateNames().getNum();
int sm = s;
tensorbuffer = copy(ss.base(),ss.base()+ny,tensorbuffer);
// write the tensors into buffer
const UnfoldDecisionRule& udr =
approximation.getUnfoldDecisionRule();
for (int i=1; i <= *ord; i++) {
const UFSTensor* t = udr.get(Symmetry(i));
#ifdef DEBUG
printf("tensor %d:\n", i);
t->print();
#endif
tensorbuffer = copy(t->base(), t->base()+ny*sm, tensorbuffer);
sm *= s;
}
// save number of endogenous states
*num_state = s-(*num_exo);
// ordering
#ifdef DEBUG
printf("all endo names:\n");
dynare.getAllEndoNames().print();
printf("all state names:\n");
dynare.getStateNames().print();
#endif
if (matchnames(endo, *num_endo, dynare.getAllEndoNames(),
0, *num_endo, ordering_endo) ||
matchnames(endo, *num_endo, dynare.getStateNames(),
0, *num_state, ordering_state) ||
matchnames(exo, *num_exo, dynare.getStateNames(),
*num_state, *num_exo, ordering_exo)) {
*error = DYNARER_NAMESMATCHINGERROR;
*errormessage = "There was a problem when matching names. This is weird and should not happen.";
return;
}
// return new init values (first column of SS matrix)
ConstVector newinit((const GeneralMatrix&) approximation.getSS(), 0);
#ifdef DEBUG
printf("new initial values:\n");
newinit.print();
#endif
copy(newinit.base(),newinit.base()+(*num_endo),newinitval);
} catch (const SylvException &e) {
*error = DYNARER_SYLVEXCEPTION;
char errorbuffer[501];
e.printMessage(errorbuffer, 500);
*errormessage = passmessage(errorbuffer);
#ifdef DEBUG
printf("Caught Sylv exception: ");
e.printMessage();
#endif
return;
} catch (const DynareException &e) {
*error = DYNARER_DYNAREEXCEPTION;
*errormessage = passmessage(e.message());
#ifdef DEBUG
printf("Caught Dynare exception: %s\n", e.message());
#endif
return;
} catch (const ogu::Exception &e) {
*error = DYNARER_OGUEXCEPTION;
*errormessage = passmessage(e.message());
#ifdef DEBUG
printf("Caught ogu::Exception: ");
e.print();
#endif
return;
} catch (const TLException &e) {
*error = DYNARER_TLEXCEPTION;
*errormessage = passmessage(e.getmessage());
#ifdef DEBUG
printf("Caugth TL exception: ");
e.print();
#endif
return;
} catch (const KordException &e) {
*error = DYNARER_KORDEXCEPTION;
*errormessage = passmessage(e.getmessage());
*kordcode = e.code(); // Kord error code
#ifdef DEBUG
printf("Caugth Kord exception: ");
e.print();
#endif
return;
}
*error = 0;
return;}
}

View File

@ -1,103 +0,0 @@
## $Id: dynareR.r 862 2006-08-04 17:34:56Z tamas $
## Copyright 2006, Tamas K Papp
dyn.load("dynareR.so") # FIXME: make it platform-independent
## FIXME hide auxiliary functions in a namespace
dynareR.indextensor <- function(ord, nume, nums) {
nume*((nums^ord-1)/(nums-1))
}
dynareR.extracttensor <- function(tensor, ord, nume, nums) {
aperm(array(tensor[dynareR.indextensor(ord,nume,nums)+(1:(nume*nums^ord))],
c(nume,rep(nums,ord))),(ord+1):1)
}
dynareR.errormessages <- c("Sylvester exception",
"Dynare exception",
"OGU exception",
"Tensor library exception",
"K-order expansion library exception",
"Error matching names")
calldynare <- function(modeleq, endo, exo, parameters, expandorder,
parval, vcovmatrix, initval=rep(1,length(endo)),
numsteps=0, jnlfile="/dev/null") {
## check type of parameters
local({
is.charvector <- function(cv) { is.character(cv) && is.vector(cv) }
stopifnot(is.charvector(modeleq) && is.charvector(endo) &&
is.charvector(exo) && is.charvector(parameters) &&
is.charvector(jnlfile))
})
stopifnot(is.numeric(expandorder) && is.vector(expandorder) &&
(length(expandorder) == 1) && (expandorder >= 0))
stopifnot(length(jnlfile) == 1)
local({ # variable names
checkvarname <- function(v) {
stopifnot(length(grep("[^a-zA-Z].*",v)) == 0) # look for strange chars
}
checkvarname(endo)
checkvarname(exo)
checkvarname(parameters)
})
stopifnot(is.vector(parval) && is.numeric(parval))
stopifnot(is.vector(initval) && is.numeric(initval))
stopifnot(is.matrix(vcovmatrix) && is.numeric(vcovmatrix))
stopifnot(is.numeric(numsteps) && is.vector(numsteps) &&
(length(numsteps)==1))
## append semicolons to model equations if necessary
modeleq <- sapply(modeleq, function(s) {
if (length(grep("^.*; *$",s))==1)
s
else
sprintf("%s;",s)
})
## then concatenate into a single string
modeleq <- paste(modeleq, collapse=" ")
## call dynareR
nume <- length(endo)
maxs <- length(endo)+length(exo)
dr <- .C("dynareR",
endo,as.integer(nume),
exo,as.integer(length(exo)),
parameters,as.integer(length(parameters)),
modeleq,as.integer(expandorder),jnlfile,
as.double(parval),as.double(vcovmatrix),
as.double(initval),
as.integer(numsteps),
tensorbuffer=double(dynareR.indextensor(expandorder+1,nume,maxs)),
numstate=integer(1), orderstate=integer(maxs),
orderendo=integer(nume),
orderexo=integer(length(exo)),
newinitval=double(nume),
error=integer(1),
errormessage=character(1),
kordcode=integer(1))
## check for errors
kordcode <- 0
if (dr$error == 0) {
if (dr$error == 5) {
list(kordcode=dr$kordcode - 251) # magic dynare++ constant
} else {
## return result
with(dr, {
nums <- numstate+length(exo)
list(ss=dynareR.extracttensor(dr$tensorbuffer,0,nume,nums), # ss
rule=sapply(1:expandorder,function (o) { # decision rule
dynareR.extracttensor(dr$tensorbuffer,o,nume,nums)
}),
orderstate=orderstate[1:numstate], # state ordering
orderendo=orderendo, # endog. ordering
orderexo=orderexo, # exog. ordering
newinitval=newinitval, # new init values
kordcode=0)
})
}
} else {
stop(sprintf("%s (\"%s\")",dynareR.errormessages[dr$error],
dr$errormessage))
}
}

View File

@ -1,201 +0,0 @@
%% $Id: dynareR.tex 863 2006-08-04 17:35:21Z tamas $
%% Copyright Tamas K Papp, 2006
%% should compile with any reasonable TeX distribution, I am using tetex
\documentclass[12pt,a4paper]{article}
\usepackage{amsmath}
\usepackage{amsfonts}
%\usepackage[letterpaper,vmargin=1.7in]{geometry}
%\usepackage[letterpaper,left=2cm,right=8cm,bottom=3cm,top=3cm,marginparwidth=4cm]{geometry}
%\usepackage{natbib}
\usepackage{graphicx}
\usepackage{url}
\usepackage{natbib}
\usepackage{color}
\usepackage{paralist} % compactitem
\DeclareMathOperator{\Var}{Var}
\DeclareMathOperator{\Cov}{Cov}
\DeclareMathOperator{\argmin}{argmin}
\DeclareMathOperator{\argmax}{argmax}
\DeclareMathSymbol{\ueps}{\mathord}{letters}{"0F} % ugly epsilon
\renewcommand{\epsilon}{\varepsilon}
\newcommand{\aseq}{\overset{as}=} % almost surely equals
\usepackage{fancyhdr}
\pagestyle{fancy}
\lhead{Tam\'as K Papp} \chead{} \rhead{DynareR}
\cfoot{\thepage}
\renewcommand\floatpagefraction{.9}
\renewcommand\topfraction{.9}
\renewcommand\bottomfraction{.9}
\renewcommand\textfraction{.1}
\usepackage{listings}
\lstset{
language=R,
extendedchars=true,
basicstyle=\footnotesize,
stringstyle=\ttfamily,
commentstyle=\slshape,
% numbers=left,
% stepnumber=5,
% numbersep=6pt,
% numberstyle=\footnotesize,
breaklines=true,
frame=single,
columns=fullflexible,
}
\begin{document}
\title{DynareR}
\author{Tam\'as K Papp (\url{tpapp@princeton.edu})}
\date{\today}
\maketitle
DynareR is an R interface for Ondra Kamen\'ik's Dynare++ program. The
interface is still under development, and the functions might change.
However, I thought that some documentation would help to get users
started.
The purpose of DynareR is to return the transition rule (the
steady state and a list of tensors) for a given model. DynareR
does not simulate, and currently does no checking of the
approximation. Primarily, the interface is to be intended to be used
in Bayesian estimation of DSGE models (via MCMC).
Before you read on, make sure that
\begin{compactitem}
\item you understand what Dynare++ is and how it works,
\item you have compiled Dynare++ and DynareR (see \verb!README! in
\verb!extern/R!), and placed \verb!dynareR.so! and
\verb!dynareR.r! in your load path for R.
\end{compactitem}
The function that performs all the work is called
\lstinline{calldynare}. Its is defined like this:
\begin{lstlisting}
calldynare <- function(modeleq, endo, exo, parameters, expandorder,
parval, vcovmatrix, initval=rep(1,length(endo)),
numsteps=0, jnlfile="/dev/null") {
...
}
\end{lstlisting}
\lstinline{modeleq} is a character vector for the model equations, and
it may have a length longer than one. First, \lstinline{calldynare}
checks if each string in the vector has a terminating semicolon (may
be followed by whitespace), if it doesn't, then it appends one. Then
it concatenates all equations into a single string. Thus, the
following versions of \lstinline{modeleq} give equivalent results:
\begin{lstlisting}
modeleq1 <- c("(c/c(1))^gamma*beta*(alpha*exp(a(1))*k^(alpha-1)+1-delta)=1",
"a=rho*a(-1)+eps",
"k+c=exp(a)*k(-1)^alpha+(1-delta)*k(-1)")
modeleq2 <- c("(c/c(1))^gamma*beta*(alpha*exp(a(1))*k^(alpha-1)+1-delta)=1;",
"a=rho*a(-1)+eps ; ",
"k+c=exp(a)*k(-1)^alpha+(1-delta)*k(-1) \t;\t ")
modeleq3 <- paste(modeleq1, collapse=" ")
\end{lstlisting}
The next three arguments name the endo- and exogenous variables and
the parameters. The names should be character vectors, for example,
\begin{lstlisting}
parameters <- c("beta","gamma","rho","alpha","delta")
varendo <- c("k","c","a")
varexo <- "eps"
\end{lstlisting}
\lstinline{calldynare} also needs the order of the approximation
\lstinline{expandorder} (a nonnegative integer), the parameter values
\lstinline{parval} (should be the same length as
\lstinline{parameters}), a variance-covariance matrix \lstinline{vcov}
(dimensions should match the length of \lstinline{exo}) and initial
values for finding the deterministic steady state
(\lstinline{initval}). If you don't provide initial values,
\lstinline{calldynare} will use a sequence of $1$s, on the assumption
that most variables in economics are positive --- you should always
try to provide a reasonable initial guess for the nonlinear solver if
possible (if you are doing MCMC, chances are that you only have to do
it once, see \lstinline{newinitval} below).
You can also provide the number of steps for calculating the
stochastic steady state (\lstinline{numsteps}, the default is zero,
see the dynare++ tutorial for more information) and the name of the
journal file \lstinline{jnlfile}. If you don't provide a journal
file, the default is \verb!/dev/null!.
Below, you see an example of using dynareR.
\lstinputlisting{test.r}
\lstinline{calldynare} returns the results in a list, variables below
refer to elements of this list. First, you should always check
\lstinline{kordcode}, which tells whether dynare++ could calculate an
approximation. It can have the following values:
\begin{description}
\item[0] the calculation was successful
\item[1] the system is not stable (Blanchard-Kahn)
\item[2] failed to calculate fixed point (infinite values)
\item[3] failed to calculate fixed point (NaN values)
\end{description}
If \lstinline{kordcode} is nonzero, then the list has only this
element.
If \lstinline{kordcode} equals zero, then the list has the following
elements:
\begin{description}
\item[ss] the steady state (ordered by \lstinline{orderendo}), which
is a vector
\item[rule] the transition rule (ordered by \lstinline{orderendo},
\lstinline{orderstate} and \lstinline{orderexo}), a list of arrays
\item[newinitval] the deterministic steady state, you can use this to
initialize the nonlinear solver for a nearby point in the parameter
space (ordered by \lstinline{orderendo})
\item[orderstate] the index of endogenous variables that ended up in
the state
\item[orderendo] the ordering of endogenous variables
\item[orderexo] the ordering of exogenous variables
\item[kordcode] discussed above
\end{description}
An example will illustrate the ordering. To continue the example above,
\begin{lstlisting}
> dd$orderstate
[1] 1 3
> dd$orderendo
[1] 1 3 2
> dd$orderexo
[1] 1
> dd$rule[[1]]
[,1] [,2] [,3]
[1,] 0.9669374 0.0 0.02071077
[2,] 2.4230073 0.9 0.45309125
[3,] 2.6922303 1.0 0.50343473
\end{lstlisting}
Recall that the original ordering of endogenous variables was
\lstinline{k, c, a}. The vectors and matrices of the result are
ordered as \lstinline{varendo[dd$orderendo]}, that is, as
\lstinline{k, a, c}. This is the ordering for the steady state and
the first dimension of the tensors in \lstinline{rule}. The other
dimensions are ordered as
\lstinline{c(varendo[dd$orderstate],varexo[dd$orderexo])}, that is to
say, as \lstinline{k, a, eps}. Use these orderings when calculating
with the tensors and the steady state. Also, remember that the $i$th
tensor is already divided by $i!$.
\lstinline{calldynare} also handles exceptions from dynare. All
exceptions (except KordException, which sets \lstinline{kordcode})
generate an error in the R interface. Normally, when solving a
well-formed model (no typos in the equations, etc), users should not
encounter these exceptions. Having a journal file is useful for
debugging. If you are making long calculations, it is reasonable to
catch errors with \lstinline{try} so that they won't abort the
calculation.
% \bibliographystyle{apalike}
% \bibliography{/home/tpapp/doc/general.bib}
\end{document}
%%% Local Variables:
%%% mode: latex
%%% TeX-master: t
%%% End:

View File

@ -1,32 +0,0 @@
#include "dynareR.cpp"
int main(void) {
const char *parameters[] = {"beta","gamma","rho","alpha","delta"};
const char *varendo[] = {"k","c","a"};
const char *varexo[] = {"eps"};
const int numpar = 5;
const int numendo = 3;
const int numexo = 1;
const int ord = 2;
const int numsteps = 0;
const double parval[] = {.99,2,.9,.3,.025};
const double vcov[] = {0.001};
const double initval[] = {0.066, 0.43, 0.01};
int e;
double tensorbuffer[100];
int num_state;
int ordering_state[] = {0,0,0};
int ordering_endo[] = {0,0,0};
int ordering_exo[] = {0};
double newinitval[] = {0,0,0};
const char *modeleq[] = {"(c/c(1))^gamma*beta*(alpha*exp(a(1))*k^(alpha-1)+1-delta)=1; a=rho*a(-1)+eps; k+c=exp(a)*k(-1)^alpha+(1-delta)*k(-1);"};
dynareR(varendo, &numendo, varexo, &numexo, parameters, &numpar, modeleq,
&ord, "journal", parval, vcov, initval,
&numsteps, tensorbuffer,
&num_state, ordering_state, ordering_endo, ordering_exo,
newinitval,&e);
printf("error code: %d\n", e);
}

View File

@ -1,15 +0,0 @@
source("dynareR.r")
parameters <- c("beta","gamma","rho","alpha","delta")
varendo <- c("k","c","a")
varexo <- "eps"
parval <- c(.99,2,.9,.3,.025)
vcovmatrix <- matrix(1,1,1)
initval <- c(0.066, 0.43, 0.01)
modeleq <- c("(c/c(1))^gamma*beta*(alpha*exp(a(1))*k^(alpha-1)+1-delta)=1",
"a=rho*a(-1)+eps",
"k+c=exp(a)*k(-1)^alpha+(1-delta)*k(-1)")
dd <- calldynare(modeleq,varendo,varexo,parameters,2,parval,vcovmatrix,initval)

View File

@ -1,129 +0,0 @@
// Copyright (C) 2005-2011, Ondra Kamenik
// This is the mexFunction providing interface to
// DecisionRule<>::simulate(). It takes the following input
// parameters:
// order the order of approximation, needs order+1 derivatives
// nstat
// npred
// nboth
// nforw
// nexog
// ystart starting value (full vector of endogenous)
// shocks matrix of shocks (nexog x number of period)
// vcov covariance matrix of shocks (nexog x nexog)
// seed integer seed
// ysteady full vector of decision rule's steady
// ... order+1 matrices of derivatives
// output:
// res simulated results
#include "dynmex.h"
#include "mex.h"
#include "decision_rule.h"
#include "fs_tensor.h"
#include "SylvException.h"
extern "C" {
void mexFunction(int nlhs, mxArray* plhs[],
int nhrs, const mxArray* prhs[])
{
if (nhrs < 12 || nlhs != 2)
DYN_MEX_FUNC_ERR_MSG_TXT("dynare_simul_ must have at least 12 input parameters and exactly 2 output arguments.\n");
int order = (int)mxGetScalar(prhs[0]);
if (nhrs != 12 + order)
DYN_MEX_FUNC_ERR_MSG_TXT("dynare_simul_ must have exactly 11+order input parameters.\n");
int nstat = (int)mxGetScalar(prhs[1]);
int npred = (int)mxGetScalar(prhs[2]);
int nboth = (int)mxGetScalar(prhs[3]);
int nforw = (int)mxGetScalar(prhs[4]);
int nexog = (int)mxGetScalar(prhs[5]);
const mxArray* const ystart = prhs[6];
const mxArray* const shocks = prhs[7];
const mxArray* const vcov = prhs[8];
int seed = (int)mxGetScalar(prhs[9]);
const mxArray* const ysteady = prhs[10];
const mwSize* const ystart_dim = mxGetDimensions(ystart);
const mwSize* const shocks_dim = mxGetDimensions(shocks);
const mwSize* const vcov_dim = mxGetDimensions(vcov);
const mwSize* const ysteady_dim = mxGetDimensions(ysteady);
int ny = nstat + npred + nboth + nforw;
if (ny != (int) ystart_dim[0])
DYN_MEX_FUNC_ERR_MSG_TXT("ystart has wrong number of rows.\n");
if (1 != ystart_dim[1])
DYN_MEX_FUNC_ERR_MSG_TXT("ystart has wrong number of cols.\n");
int nper = shocks_dim[1];
if (nexog != (int) shocks_dim[0])
DYN_MEX_FUNC_ERR_MSG_TXT("shocks has a wrong number of rows.\n");
if (nexog != (int) vcov_dim[0])
DYN_MEX_FUNC_ERR_MSG_TXT("vcov has a wrong number of rows.\n");
if (nexog != (int) vcov_dim[1])
DYN_MEX_FUNC_ERR_MSG_TXT("vcov has a wrong number of cols.\n");
if (ny != (int) ysteady_dim[0])
DYN_MEX_FUNC_ERR_MSG_TXT("ysteady has wrong number of rows.\n");
if (1 != ysteady_dim[1])
DYN_MEX_FUNC_ERR_MSG_TXT("ysteady has wrong number of cols.\n");
mxArray* res = mxCreateDoubleMatrix(ny, nper, mxREAL);
try {
// initialize tensor library
tls.init(order, npred+nboth+nexog);
// form the polynomial
UTensorPolynomial pol(ny, npred+nboth+nexog);
for (int dim = 0; dim <= order; dim++) {
const mxArray* gk = prhs[11+dim];
const mwSize* const gk_dim = mxGetDimensions(gk);
FFSTensor ft(ny, npred+nboth+nexog, dim);
if (ft.ncols() != (int) gk_dim[1]) {
char buf[1000];
sprintf(buf, "Wrong number of columns for folded tensor: got %d but I want %d\n",
(int) gk_dim[1], ft.ncols());
DYN_MEX_FUNC_ERR_MSG_TXT(buf);
}
if (ft.nrows() != (int) gk_dim[0]) {
char buf[1000];
sprintf(buf, "Wrong number of rows for folded tensor: got %d but I want %d\n",
(int) gk_dim[0], ft.nrows());
DYN_MEX_FUNC_ERR_MSG_TXT(buf);
}
ft.zeros();
ConstTwoDMatrix gk_mat(ft.nrows(), ft.ncols(), mxGetPr(gk));
ft.add(1.0, gk_mat);
UFSTensor* ut = new UFSTensor(ft);
pol.insert(ut);
}
// form the decision rule
UnfoldDecisionRule
dr(pol, PartitionY(nstat, npred, nboth, nforw),
nexog, ConstVector(mxGetPr(ysteady), ny));
// form the shock realization
TwoDMatrix shocks_mat(nexog, nper, (const double*)mxGetPr(shocks));
TwoDMatrix vcov_mat(nexog, nexog, (const double*)mxGetPr(vcov));
GenShockRealization sr(vcov_mat, shocks_mat, seed);
// simulate and copy the results
Vector ystart_vec((const double*)mxGetPr(ystart), ny);
TwoDMatrix* res_mat =
dr.simulate(DecisionRule::horner, nper,
ystart_vec, sr);
TwoDMatrix res_tmp_mat(ny, nper, mxGetPr(res));
res_tmp_mat = (const TwoDMatrix&)(*res_mat);
delete res_mat;
plhs[1] = res;
} catch (const KordException& e) {
DYN_MEX_FUNC_ERR_MSG_TXT("Caugth Kord exception.");
} catch (const TLException& e) {
DYN_MEX_FUNC_ERR_MSG_TXT("Caugth TL exception.");
} catch (SylvException& e) {
DYN_MEX_FUNC_ERR_MSG_TXT("Caught Sylv exception.");
}
plhs[0] = mxCreateDoubleScalar(0);
}
};

View File

@ -1,174 +0,0 @@
%
% SYNOPSIS
%
% r = dynare_simul(name, shocks)
% r = dynare_simul(name, prefix, shocks)
% r = dynare_simul(name, shocks, start)
% r = dynare_simul(name, prefix, shocks, start)
%
% name name of MAT-file produced by dynare++
% prefix prefix of variables in the MAT-file
% shocks matrix of shocks
% start zero period value
%
% Note that this file requires the dynare_simul_ DLL to be in the path.
% This DLL is distributed with Dynare, under the mex/matlab or mex/octave
% subdirectory.
%
% SEMANTICS
%
% The command reads a decision rule from the MAT-file having the given
% prefix. Then it starts simulating the decision rule with zero time value
% equal to the given start. It uses the given shocks for the simulation. If
% the start is not given, the state about which the decision rule is
% centralized is taken (called fix point, or stochastic steady state, take
% your pick).
%
% prefix Use the prefix with which you called dynare++, the default
% prefix in dynare++ is 'dyn'.
% shocks Number of rows must be a number of exogenous shocks,
% number of columns gives the number of simulated
% periods. NaNs and Infs in the matrix are substitued by
% draws from the normal distribution using the covariance
% matrix given in the model file.
% start Vector of endogenous variables in the ordering given by
% <prefix>_vars.
%
% Seed for random generator is derived from calling rand(1,1). Therefore,
% seeding can be controlled with rand('state') and rand('state',some_seed).
%
% EXAMPLES
%
% All examples suppose that the prefix is 'dyn' and that your_model.mat
% has been loaded into Matlab.
%
% 1. response to permanent negative shock to the third exo var EPS3 for
% 100 periods
%
% shocks = zeros(4,100); % 4 exogenous variables in the model
% shocks(dyn_i_EPS3,:) = -0.1; % the permanent shock to EPS3
% r = dynare_simul('your_model.mat',shocks);
%
% 2. one stochastic simulation for 100 periods
%
% shocks = zeros(4,100)./0; % put NaNs everywhere
% r = dynare_simul('your_model.mat',shocks);
%
% 3. one stochastic simulation starting at 75% undercapitalized economy
%
% shocks = zeros(4,100)./0; % put NaNs everywhere
% ystart = dyn_ss; % get copy of DR fix point
% ystart(dyn_i_K) = 0.75*dyn_ss(dyn_i_K); % scale down the capital
% r = dynare_simul('your_model.mat',shocks,ystart);
%
%
% SEE ALSO
%
% "DSGE Models with Dynare++. A Tutorial.", Ondra Kamenik, 2005
% Copyright (C) 2005-2011, Ondra Kamenik
function r = dynare_simul(varargin)
if exist('dynare_simul_') ~= 3
error('Can''t find dynare_simul_ DLL in the path. The simplest way to add it is to run Dynare once in this session.')
end
% get the file name and load data
fname = varargin{1};
eval(['load ' fname]);
% set prefix, shocks, ystart
if ischar(varargin{2})
prefix = varargin{2};
if length(varargin) == 3
shocks = varargin{3};
ystart = NaN;
elseif length(varargin) == 4
shocks = varargin{3};
ystart = varargin{4};
else
error('Wrong number of parameters.');
end
else
prefix = 'dyn';
if length(varargin) == 2
shocks = varargin{2};
ystart = NaN;
elseif length(varargin) == 3
shocks = varargin{2};
ystart = varargin{3};
else
error('Wrong number of parameters.');
end
end
% load all needed variables but prefix_g_*
if (exist([prefix '_nstat']))
nstat = eval([prefix '_nstat']);
else
error(['Could not find variable ' prefix '_nstat in workspace']);
end
if (exist([prefix '_npred']))
npred = eval([prefix '_npred']);
else
error(['Could not find variable ' prefix '_npred in workspace']);
end
if (exist([prefix '_nboth']))
nboth = eval([prefix '_nboth']);
else
error(['Could not find variable ' prefix '_nboth in workspace']);
end
if (exist([prefix '_nforw']))
nforw = eval([prefix '_nforw']);
else
error(['Could not find variable ' prefix '_nforw in workspace']);
end
if (exist([prefix '_ss']))
ss = eval([prefix '_ss']);
else
error(['Could not find variable ' prefix '_ss in workspace']);
end
if (exist([prefix '_vcov_exo']))
vcov_exo = eval([prefix '_vcov_exo']);
else
error(['Could not find variable ' prefix '_vcov_exo in workspace']);
end
nexog = size(vcov_exo,1);
if isnan(ystart)
ystart = ss;
end
% newer version of dynare++ doesn't return prefix_g_0, we make it here if
% it does not exist in workspace
g_zero = [prefix '_g_0'];
if (~ exist(g_zero))
eval([ g_zero '= zeros(nstat+npred+nboth+nforw,1);']);
end
% make derstr a string of comma seperated existing prefix_g_*
derstr = [',' g_zero];
order = 1;
cont = 1;
while cont == 1
g_ord = [prefix '_g_' num2str(order)];
if (exist(g_ord))
derstr = [derstr ',' g_ord];
order = order + 1;
else
cont = 0;
end
end
% set seed
seed = ceil(10000*rand(1,1));
% call dynare_simul_
command = ['[err,r]=dynare_simul_(' num2str(order-1) ',nstat,npred,nboth,nforw,' ...
'nexog,ystart,shocks,vcov_exo,seed,ss' derstr ');'];
eval(command);
if err
error('Simulation failed')
end

View File

@ -1,54 +1,16 @@
CWEBSRC = \
product.cweb \
quadrature.cweb \
quasi_mcarlo.cweb \
smolyak.cweb \
vector_function.cweb \
product.hweb \
quadrature.hweb \
quasi_mcarlo.hweb \
smolyak.hweb \
vector_function.hweb
GENERATED_FILES = \
product.cpp \
quadrature.cpp \
quasi_mcarlo.cpp \
smolyak.cpp \
vector_function.cpp \
product.h \
quadrature.h \
quasi_mcarlo.h \
smolyak.h \
vector_function.h
noinst_LIBRARIES = libinteg.a
libinteg_a_SOURCES = $(CWEBSRC) $(GENERATED_FILES) precalc_quadrature.dat
libinteg_a_CPPFLAGS = -I../../sylv/cc -I../../tl/cc -I$(top_srcdir)/mex/sources
libinteg_a_CXXFLAGS = $(AM_CXXFLAGS) $(PTHREAD_CFLAGS)
BUILT_SOURCES = $(GENERATED_FILES)
EXTRA_DIST = main.web dummy.ch
%.cpp: %.cweb dummy.ch
$(CTANGLE) -bhp $< dummy.ch $@
%.h: %.hweb dummy.ch
$(CTANGLE) -bhp $< dummy.ch $@
if HAVE_CWEAVE
if HAVE_PDFTEX
if HAVE_EPLAIN
pdf-local: integ.pdf
integ.pdf: main.web $(CWEBSRC)
$(CWEAVE) -bhp main.web
$(PDFTEX) main
mv main.pdf integ.pdf
endif
endif
endif
CLEANFILES = integ.pdf main.idx main.log main.scn main.tex main.toc
libinteg_a_SOURCES = \
quadrature.cc \
quadrature.hh \
quasi_mcarlo.cc \
quasi_mcarlo.hh \
product.cc \
product.hh \
smolyak.cc \
smolyak.hh \
vector_function.cc \
vector_function.hh \
precalc_quadrature.hh
libinteg_a_CPPFLAGS = -I../../sylv/cc -I../../utils/cc -I../../tl/cc -I$(top_srcdir)/mex/sources
libinteg_a_CXXFLAGS = $(AM_CXXFLAGS) $(THREAD_CXXFLAGS)

View File

@ -1,48 +0,0 @@
@q $Id: main.web 2333 2009-01-14 10:32:55Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@q cwebmac.tex defines its own \ifpdf, which is incompatible with the @>
@q \ifpdf defined by eplain, so undefine it @>
\let\ifpdf\relax
\input eplain
@q now define \ifpdf to be always false: PDF macros of cwebmac are buggy @>
\newif\ifpdf
\iffalse\fi
\def\title{{\mainfont Numerical Integration Module}}
@i ../../c++lib.w
@s Vector int
@s ConstVector int
@s IntSequence int
@s GeneralMatrix int
@s THREAD int
@s THREAD_GROUP int
@s SYNCHRO int
\titletrue
\null\vfill
\centerline{\titlefont Numerical Integration Module}
\vfill\vfill
Copyright \copyright\ 2005 by Ondra Kamenik
\penalty-10000
@i vector_function.hweb
@i vector_function.cweb
@i quadrature.hweb
@i quadrature.cweb
@i product.hweb
@i product.cweb
@i smolyak.hweb
@i smolyak.cweb
@i quasi_mcarlo.hweb
@i quasi_mcarlo.cweb

View File

@ -1,25 +1,42 @@
// $Id: precalc_quadrature.dat 431 2005-08-16 15:41:01Z kamenik $
// Copyright 2005, Ondra Kamenik
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
// The file contains one dimensional quadrature points and weights for
// a few quadratures. The format of data is clear. There is a class
// OneDPrecalcQuadrature which implements an interface OneDQuadrature
// using the data of this format.
// The file contains one dimensional quadrature points and weights for a few
// quadratures. The format of data is clear. There is a class
// OneDPrecalcQuadrature which implements an interface OneDQuadrature using the
// data of this format.
// Gauss-Hermite quadrature; prefix gh
// number of levels
// Number of levels
static const int gh_num_levels = 26;
// number of points in each level
// Number of points in each level
static const int gh_num_points[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
30, 32, 40, 50, 60, 64
};
// weights, starting with the first level
// Weights, starting with the first level
static const double gh_weights[] = {
// weights 1 = sqrt(pi)
// weights 1 = √π
1.77245385090551588191942755656782537698745727539062,
// weights 2
0.886226925452758013649083741671e+00,
@ -533,7 +550,7 @@ static const double gh_weights[] = {
0.553570653584e-48
};
// points, starting with the first level
// Points, starting with the first level
static const double gh_points[] = {
// points 1
0.0,
@ -1051,16 +1068,16 @@ static const double gh_points[] = {
// Gauss-Legendre quadrature; prefix gl
// number of levels
// Number of levels
static const int gl_num_levels = 22;
// number of points in each level
// Number of points in each level
static const int gl_num_points[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
32, 64
};
// weights, starting with the first level
// Weights, starting with the first level
static const double gl_weights[] = {
// weight 1
2.0e+00,
@ -1392,7 +1409,7 @@ static const double gl_weights[] = {
0.178328072169643294729607914497e-02
};
// points, starting with the first level
// Points, starting with the first level
static const double gl_points[] = {
// points 1
0.0e+00,
@ -1723,99 +1740,3 @@ static const double gl_points[] = {
0.996340116771955279346924500676e+00,
0.999305041735772139456905624346e+00
};
// this is the positive half of normal inverse cum distribution
// function starting at 0.5 and ending at 0.998, with step 0.002
static const int normal_icdf_num = 250;
static const double normal_icdf_end = 0.998;
static const double normal_icdf_step = 0.002;
static const double normal_icdf_data[] = {
0, 5.013277548926632e-03, 1.002668110027482e-02,
1.504033667863573e-02, 2.005437035295075e-02, 2.506890825871118e-02,
3.008407662018906e-02, 3.510000177270896e-02, 4.011681018496811e-02,
4.513462848142118e-02, 5.015358346473358e-02, 5.517380213831685e-02,
6.019541172895673e-02, 6.521853970954372e-02, 7.024331382191684e-02,
7.526986209982979e-02, 8.029831289205518e-02, 8.532879488562921e-02,
9.036143712925872e-02, 9.539636905689193e-02, 1.004337205114700e-01,
1.054736217688682e-01, 1.105162035620419e-01, 1.155615971053833e-01,
1.206099341193073e-01, 1.256613468550742e-01, 1.307159681198632e-01,
1.357739313021116e-01, 1.408353703971274e-01, 1.459004200329941e-01,
1.509692154967774e-01, 1.560418927610502e-01, 1.611185885107454e-01,
1.661994401703590e-01, 1.712845859315068e-01, 1.763741647808615e-01,
1.814683165284770e-01, 1.865671818365194e-01, 1.916709022484199e-01,
1.967796202184666e-01, 2.018934791418509e-01, 2.070126233851871e-01,
2.121371983175242e-01, 2.172673503418634e-01, 2.224032269272064e-01,
2.275449766411493e-01, 2.326927491830447e-01, 2.378466954177492e-01,
2.430069674099821e-01, 2.481737184593126e-01, 2.533471031357997e-01,
2.585272773163098e-01, 2.637143982215299e-01, 2.689086244537098e-01,
2.741101160351471e-01, 2.793190344474543e-01, 2.845355426716215e-01,
2.897598052289143e-01, 2.949919882226262e-01, 3.002322593807220e-01,
3.054807880993972e-01, 3.107377454875922e-01, 3.160033044124830e-01,
3.212776395459965e-01, 3.265609274123727e-01, 3.318533464368166e-01,
3.371550769952773e-01, 3.424663014653906e-01, 3.477872042786273e-01,
3.531179719736894e-01, 3.584587932511938e-01, 3.638098590296960e-01,
3.691713625030897e-01, 3.745434991994428e-01, 3.799264670413076e-01,
3.853204664075677e-01, 3.907257001968699e-01, 3.961423738926983e-01,
4.015706956301487e-01, 4.070108762644656e-01, 4.124631294414047e-01,
4.179276716694820e-01, 4.234047223941831e-01, 4.288945040742017e-01,
4.343972422597815e-01, 4.399131656732339e-01, 4.454425062917200e-01,
4.509854994323708e-01, 4.565423838398405e-01, 4.621134017763774e-01,
4.676987991145082e-01, 4.732988254324370e-01, 4.789137341122557e-01,
4.845437824410792e-01, 4.901892317152095e-01, 4.958503473474533e-01,
5.015273989777081e-01, 5.072206605869456e-01, 5.129304106147284e-01,
5.186569320803909e-01, 5.244005127080407e-01, 5.301614450555191e-01,
5.359400266474903e-01, 5.417365601128169e-01, 5.475513533264015e-01,
5.533847195556728e-01, 5.592369776119069e-01, 5.651084520065839e-01,
5.709994731129874e-01, 5.769103773332714e-01, 5.828415072712163e-01,
5.887932119109195e-01, 5.947658468016782e-01, 6.007597742493188e-01,
6.067753635142652e-01, 6.128129910166273e-01, 6.188730405486286e-01,
6.249559034946875e-01, 6.310619790594989e-01, 6.371916745044747e-01,
6.433454053929173e-01, 6.495235958443252e-01, 6.557266787982537e-01,
6.619550962881621e-01, 6.682092997257233e-01, 6.744897501960819e-01,
6.807969187645747e-01, 6.871312867954694e-01, 6.934933462832894e-01,
6.998836001973414e-01, 7.063025628400875e-01, 7.127507602200432e-01,
7.192287304399239e-01, 7.257370241008051e-01, 7.322762047230997e-01,
7.388468491852137e-01, 7.454495481807891e-01, 7.520849066954916e-01,
7.587535445043710e-01, 7.654560966908778e-01, 7.721932141886847e-01,
7.789655643475453e-01, 7.857738315244843e-01, 7.926187177017122e-01,
7.995009431327367e-01, 8.064212470182405e-01, 8.133803882134047e-01,
8.203791459684610e-01, 8.274183207043821e-01, 8.344987348257406e-01,
8.416212335729145e-01, 8.487866859159668e-01, 8.559959854926823e-01,
8.632500515934207e-01, 8.705498301956541e-01, 8.778962950512290e-01,
8.852904488296417e-01, 8.927333243208563e-01, 9.002259857014339e-01,
9.077695298680560e-01, 9.153650878428145e-01, 9.230138262549803e-01,
9.307169489043392e-01, 9.384756984115684e-01, 9.462913579615760e-01,
9.541652531461944e-01, 9.620987539131418e-01, 9.700932766287370e-01,
9.781502862624715e-01, 9.862712987022384e-01, 9.944578832097529e-01,
1.002711665026549e+00, 1.011034328141817e+00, 1.019427618234370e+00,
1.027893345802143e+00, 1.036433389493790e+00, 1.045049699658389e+00,
1.053744302130666e+00, 1.062519302270867e+00, 1.071376889280213e+00,
1.080319340814956e+00, 1.089349027924277e+00, 1.098468420339863e+00,
1.107680092147800e+00, 1.116986727876610e+00, 1.126391129038801e+00,
1.135896221167312e+00, 1.145505061392697e+00, 1.155220846611952e+00,
1.165046922305602e+00, 1.174986792066090e+00, 1.185044127907810e+00,
1.195222781437427e+00, 1.205526795972518e+00, 1.215960419707319e+00,
1.226528120036610e+00, 1.237234599162827e+00, 1.248084811127547e+00,
1.259083980427072e+00, 1.270237622393149e+00, 1.281551565544601e+00,
1.293031976144243e+00, 1.304685385228790e+00, 1.316518718418261e+00,
1.328539328856810e+00, 1.340755033690217e+00, 1.353174154548003e+00,
1.365805562572272e+00, 1.378658728623277e+00, 1.391743779396326e+00,
1.405071560309632e+00, 1.418653706172739e+00, 1.432502720825812e+00,
1.446632067158978e+00, 1.461056269186906e+00, 1.475791028179170e+00,
1.490853355246661e+00, 1.506261723278244e+00, 1.522036241735856e+00,
1.538198858584064e+00, 1.554773594596853e+00, 1.571786816509860e+00,
1.589267557051392e+00, 1.607247891900218e+00, 1.625763386233235e+00,
1.644853626951473e+00, 1.664562861202721e+00, 1.684940767871913e+00,
1.706043396888962e+00, 1.727934322388419e+00, 1.750686071252170e+00,
1.774381910344958e+00, 1.799118106837967e+00, 1.825006821146403e+00,
1.852179858769047e+00, 1.880793608151250e+00, 1.911035647549119e+00,
1.943133751105067e+00, 1.977368428181947e+00, 2.014090812018140e+00,
2.053748910631823e+00, 2.096927429164343e+00, 2.144410620911840e+00,
2.197286376641053e+00, 2.257129244486226e+00, 2.326347874040842e+00,
2.408915545815460e+00, 2.512144327930459e+00, 2.652069807902199e+00,
2.878161739095476e+00
};
// Local Variables:
// mode:C++
// End:

View File

@ -0,0 +1,143 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
#include "product.hh"
#include "symmetry.hh"
#include <iostream>
#include <iomanip>
/* This constructs a product iterator corresponding to index (j0,0,…,0). */
prodpit::prodpit(const ProductQuadrature &q, int j0, int l)
: prodq(q), level(l), npoints(q.uquad.numPoints(l)),
jseq(q.dimen(), 0),
end_flag(false),
sig{q.dimen()},
p{q.dimen()}
{
if (j0 < npoints)
{
jseq[0] = j0;
setPointAndWeight();
}
else
end_flag = true;
}
bool
prodpit::operator==(const prodpit &ppit) const
{
return &prodq == &ppit.prodq && end_flag == ppit.end_flag && jseq == ppit.jseq;
}
prodpit &
prodpit::operator++()
{
int i = prodq.dimen()-1;
jseq[i]++;
while (i >= 0 && jseq[i] == npoints)
{
jseq[i] = 0;
i--;
if (i >= 0)
jseq[i]++;
}
sig.signalAfter(std::max(i, 0));
if (i == -1)
end_flag = true;
if (!end_flag)
setPointAndWeight();
return *this;
}
/* This calculates the weight and sets point coordinates from the indices. */
void
prodpit::setPointAndWeight()
{
w = 1.0;
for (int i = 0; i < prodq.dimen(); i++)
{
p[i] = (prodq.uquad).point(level, jseq[i]);
w *= (prodq.uquad).weight(level, jseq[i]);
}
}
/* Debug print. */
void
prodpit::print() const
{
auto ff = std::cout.flags();
std::cout << "j=[";
for (int i = 0; i < prodq.dimen(); i++)
std::cout << std::setw(2) << jseq[i];
std::cout << std::showpos << std::fixed << std::setprecision(3)
<< "] " << std::setw(4) << w << "*(";
for (int i = 0; i < prodq.dimen()-1; i++)
std::cout << std::setw(4) << p[i] << ' ';
std::cout << std::setw(4) << p[prodq.dimen()-1] << ')' << std::endl;
std::cout.flags(ff);
}
ProductQuadrature::ProductQuadrature(int d, const OneDQuadrature &uq)
: QuadratureImpl<prodpit>(d), uquad(uq)
{
// TODO: check d≥1
}
/* This calls prodpit constructor to return an iterator which points
approximatelly at ti-th portion out of tn portions. First we find
out how many points are in the level, and then construct an interator
(j0,0,,0) where j0=ti·npoints/tn. */
prodpit
ProductQuadrature::begin(int ti, int tn, int l) const
{
// TODO: raise if l<dimen()
// TODO: check l ≤ uquad.numLevels()
int npoints = uquad.numPoints(l);
return prodpit(*this, ti*npoints/tn, l);
}
/* This just starts at the first level and goes to a higher level as long as a
number of evaluations (which is n for k being the level) is less than the
given number of evaluations. */
void
ProductQuadrature::designLevelForEvals(int max_evals, int &lev, int &evals) const
{
int last_evals;
evals = 1;
lev = 1;
do
{
lev++;
last_evals = evals;
evals = numEvals(lev);
}
while (lev < uquad.numLevels()-2 && evals < max_evals);
lev--;
evals = last_evals;
}

View File

@ -1,213 +0,0 @@
@q $Id: product.cweb 431 2005-08-16 15:41:01Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@ This is {\tt product.cpp} file.
@c
#include "product.h"
#include "symmetry.h"
@<|prodpit| empty constructor@>;
@<|prodpit| regular constructor@>;
@<|prodpit| copy constructor@>;
@<|prodpit| destructor@>;
@<|prodpit::operator==| code@>;
@<|prodpit::operator=| code@>;
@<|prodpit::operator++| code@>;
@<|prodpit::setPointAndWeight| code@>;
@<|prodpit::print| code@>;
@<|ProductQuadrature| constructor@>;
@<|ProductQuadrature::begin| code@>;
@<|ProductQuadrature::designLevelForEvals| code@>;
@
@<|prodpit| empty constructor@>=
prodpit::prodpit()
: prodq(NULL), level(0), npoints(0), jseq(NULL),
end_flag(true), sig(NULL), p(NULL)
{
}
@ This constructs a product iterator corresponding to index $(j0,0\ldots,0)$.
@<|prodpit| regular constructor@>=
prodpit::prodpit(const ProductQuadrature& q, int j0, int l)
: prodq(&q), level(l), npoints(q.uquad.numPoints(l)), jseq(new IntSequence(q.dimen(), 0)),
end_flag(false), sig(new ParameterSignal(q.dimen())), p(new Vector(q.dimen()))
{
if (j0 < npoints) {
(*jseq)[0] = j0;
setPointAndWeight();
} else {
end_flag = true;
}
}
@ Copy constructor, clear.
@<|prodpit| copy constructor@>=
prodpit::prodpit(const prodpit& ppit)
: prodq(ppit.prodq), level(ppit.level), npoints(ppit.npoints),
end_flag(ppit.end_flag), w(ppit.w)
{
if (ppit.jseq)
jseq = new IntSequence(*(ppit.jseq));
else
jseq = NULL;
if (ppit.sig)
sig = new ParameterSignal(*(ppit.sig));
else
sig = NULL;
if (ppit.p)
p = new Vector(*(ppit.p));
else
p = NULL;
}
@
@<|prodpit| destructor@>=
prodpit::~prodpit()
{
if (jseq)
delete jseq;
if (sig)
delete sig;
if (p)
delete p;
}
@
@<|prodpit::operator==| code@>=
bool prodpit::operator==(const prodpit& ppit) const
{
bool ret = true;
ret = ret & prodq == ppit.prodq;
ret = ret & end_flag == ppit.end_flag;
ret = ret & ((jseq==NULL && ppit.jseq==NULL) ||
(jseq!=NULL && ppit.jseq!=NULL && *jseq == *(ppit.jseq)));
return ret;
}
@
@<|prodpit::operator=| code@>=
const prodpit& prodpit::operator=(const prodpit& ppit)
{
prodq = ppit.prodq;
end_flag = ppit.end_flag;
w = ppit.w;
if (jseq)
delete jseq;
if (sig)
delete sig;
if (p)
delete p;
if (ppit.jseq)
jseq = new IntSequence(*(ppit.jseq));
else
jseq = NULL;
if (ppit.sig)
sig = new ParameterSignal(*(ppit.sig));
else
sig = NULL;
if (ppit.p)
p = new Vector(*(ppit.p));
else
p = NULL;
return *this;
}
@
@<|prodpit::operator++| code@>=
prodpit& prodpit::operator++()
{
// todo: throw if |prodq==NULL| or |jseq==NULL| or |sig==NULL| or |end_flag==true|
int i = prodq->dimen()-1;
(*jseq)[i]++;
while (i >= 0 && (*jseq)[i] == npoints) {
(*jseq)[i] = 0;
i--;
if (i >= 0)
(*jseq)[i]++;
}
sig->signalAfter(std::max(i,0));
if (i == -1)
end_flag = true;
if (! end_flag)
setPointAndWeight();
return *this;
}
@ This calculates the weight and sets point coordinates from the indices.
@<|prodpit::setPointAndWeight| code@>=
void prodpit::setPointAndWeight()
{
// todo: raise if |prodq==NULL| or |jseq==NULL| or |sig==NULL| or
// |p==NULL| or |end_flag==true|
w = 1.0;
for (int i = 0; i < prodq->dimen(); i++) {
(*p)[i] = (prodq->uquad).point(level, (*jseq)[i]);
w* = (prodq->uquad).weight(level, (*jseq)[i]);
}
}
@ Debug print.
@<|prodpit::print| code@>=
void prodpit::print() const
{
printf("j=[");
for (int i = 0; i < prodq->dimen(); i++)
printf("%2d ", (*jseq)[i]);
printf("] %+4.3f*(",w);
for (int i = 0; i < prodq->dimen()-1; i++)
printf("%+4.3f ", (*p)[i]);
printf("%+4.3f)\n",(*p)[prodq->dimen()-1]);
}
@
@<|ProductQuadrature| constructor@>=
ProductQuadrature::ProductQuadrature(int d, const OneDQuadrature& uq)
: QuadratureImpl<prodpit>(d), uquad(uq)
{
// todo: check |d>=1|
}
@ This calls |prodpit| constructor to return an iterator which points
approximatelly at |ti|-th portion out of |tn| portions. First we find
out how many points are in the level, and then construct an interator
$(j0,0,\ldots,0)$ where $j0=$|ti*npoints/tn|.
@<|ProductQuadrature::begin| code@>=
prodpit ProductQuadrature::begin(int ti, int tn, int l) const
{
// todo: raise is |l<dimen()|
// todo: check |l<=uquad.numLevels()|
int npoints = uquad.numPoints(l);
return prodpit(*this, ti*npoints/tn, l);
}
@ This just starts at the first level and goes to a higher level as
long as a number of evaluations (which is $n_k^d$ for $k$ being the
level) is less than the given number of evaluations.
@<|ProductQuadrature::designLevelForEvals| code@>=
void ProductQuadrature::designLevelForEvals(int max_evals, int& lev, int& evals) const
{
int last_evals;
evals = 1;
lev = 1;
do {
lev++;
last_evals = evals;
evals = numEvals(lev);
} while (lev < uquad.numLevels()-2 && evals < max_evals);
lev--;
evals = last_evals;
}
@ End of {\tt product.cpp} file

View File

@ -0,0 +1,131 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
// Product quadrature.
/* This file defines a product multidimensional quadrature. If Qₖ$ denotes the
one dimensional quadrature, then the product quadrature Q of k level and
dimension d takes the form:
n n
Qf = w_i··w_{i_d} f(x_i,,x_{i_d})
i=1 i_d=1
which can be written in terms of the one dimensional quadrature Q as
Qf=(QQ)f
Here we define the product quadrature iterator prodpit and plug it into
QuadratureImpl to obtains ProductQuadrature. */
#ifndef PRODUCT_H
#define PRODUCT_H
#include "int_sequence.hh"
#include "vector_function.hh"
#include "quadrature.hh"
/* This defines a product point iterator. We have to maintain the following: a
pointer to product quadrature in order to know the dimension and the
underlying one dimensional quadrature, then level, number of points in the
level, integer sequence of indices, signal, the coordinates of the point and
the weight.
The point indices, signal, and point coordinates are implmented as pointers
in order to allow for empty constructor.
The constructor prodpit(const ProductQuadrature& q, int j0, int l)
constructs an iterator pointing to (j0,0,,0), which is used by begin()
dictated by QuadratureImpl. */
class ProductQuadrature;
class prodpit
{
protected:
const ProductQuadrature &prodq;
int level{0};
int npoints{0};
IntSequence jseq;
bool end_flag{true};
ParameterSignal sig;
Vector p;
double w;
public:
prodpit() = default;
prodpit(const ProductQuadrature &q, int j0, int l);
prodpit(const prodpit &ppit) = default;
~prodpit() = default;
bool operator==(const prodpit &ppit) const;
bool
operator!=(const prodpit &ppit) const
{
return !operator==(ppit);
}
prodpit &operator=(const prodpit &spit) = delete;
prodpit &operator++();
const ParameterSignal &
signal() const
{
return sig;
}
const Vector &
point() const
{
return p;
}
double
weight() const
{
return w;
}
void print() const;
protected:
void setPointAndWeight();
};
/* The product quadrature is just QuadratureImpl with the product iterator
plugged in. The object is constructed by just giving the underlying one
dimensional quadrature, and the dimension. The only extra method is
designLevelForEvals() which for the given maximum number of evaluations (and
dimension and underlying quadrature from the object) returns a maximum level
yeilding number of evaluations less than the given number. */
class ProductQuadrature : public QuadratureImpl<prodpit>
{
friend class prodpit;
const OneDQuadrature &uquad;
public:
ProductQuadrature(int d, const OneDQuadrature &uq);
~ProductQuadrature() override = default;
int
numEvals(int l) const override
{
int res = 1;
for (int i = 0; i < dimen(); i++)
res *= uquad.numPoints(l);
return res;
}
void designLevelForEvals(int max_eval, int &lev, int &evals) const;
protected:
prodpit begin(int ti, int tn, int level) const override;
};
#endif

View File

@ -1,107 +0,0 @@
@q $Id: product.hweb 431 2005-08-16 15:41:01Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@*2 Product quadrature. This is {\tt product.h} file
This file defines a product multidimensional quadrature. If $Q_k$
denotes the one dimensional quadrature, then the product quadrature
$Q$ of $k$ level and dimension $d$ takes the form
$$Qf=\sum_{i_1=1}^{n_k}\ldots\sum_{i_d=1}^{n^k}w_{i_1}\cdot\ldots\cdot w_{i_d}
f(x_{i_1},\ldots,x_{i_d})$$
which can be written in terms of the one dimensional quadrature $Q_k$ as
$$Qf=(Q_k\otimes\ldots\otimes Q_k)f$$
Here we define the product quadrature iterator |prodpit| and plug it
into |QuadratureImpl| to obtains |ProductQuadrature|.
@s prodpit int
@s ProductQuadrature int
@c
#ifndef PRODUCT_H
#define PRODUCT_H
#include "int_sequence.h"
#include "vector_function.h"
#include "quadrature.h"
@<|prodpit| class declaration@>;
@<|ProductQuadrature| class declaration@>;
#endif
@ This defines a product point iterator. We have to maintain the
following: a pointer to product quadrature in order to know the
dimension and the underlying one dimensional quadrature, then level,
number of points in the level, integer sequence of indices, signal,
the coordinates of the point and the weight.
The point indices, signal, and point coordinates are implmented as
pointers in order to allow for empty constructor.
The constructor |prodpit(const ProductQuadrature& q, int j0, int l)|
constructs an iterator pointing to $(j0,0,\ldots,0)$, which is used by
|begin| dictated by |QuadratureImpl|.
@<|prodpit| class declaration@>=
class ProductQuadrature;
class prodpit {
protected:@;
const ProductQuadrature* prodq;
int level;
int npoints;
IntSequence* jseq;
bool end_flag;
ParameterSignal* sig;
Vector* p;
double w;
public:@;
prodpit();
prodpit(const ProductQuadrature& q, int j0, int l);
prodpit(const prodpit& ppit);
~prodpit();
bool operator==(const prodpit& ppit) const;
bool operator!=(const prodpit& ppit) const
{@+ return ! operator==(ppit);@+}
const prodpit& operator=(const prodpit& spit);
prodpit& operator++();
const ParameterSignal& signal() const
{@+ return *sig;@+}
const Vector& point() const
{@+ return *p;@+}
double weight() const
{@+ return w;@+}
void print() const;
protected:@;
void setPointAndWeight();
};
@ The product quadrature is just |QuadratureImpl| with the product
iterator plugged in. The object is constructed by just giving the
underlying one dimensional quadrature, and the dimension. The only
extra method is |designLevelForEvals| which for the given maximum
number of evaluations (and dimension and underlying quadrature from
the object) returns a maximum level yeilding number of evaluations
less than the given number.
@<|ProductQuadrature| class declaration@>=
class ProductQuadrature : public QuadratureImpl<prodpit> {
friend class prodpit;
const OneDQuadrature& uquad;
public:@;
ProductQuadrature(int d, const OneDQuadrature& uq);
virtual ~ProductQuadrature()@+ {}
int numEvals(int l) const
{
int res = 1;
for (int i = 0; i < dimen(); i++)
res *= uquad.numPoints(l);
return res;
}
void designLevelForEvals(int max_eval, int& lev, int& evals) const;
protected:@;
prodpit begin(int ti, int tn, int level) const;
};
@ End of {\tt product.h} file

View File

@ -0,0 +1,42 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
#include "quadrature.hh"
#include "precalc_quadrature.hh"
#include <cmath>
void
OneDPrecalcQuadrature::calcOffsets()
{
offsets[0] = 0;
for (int i = 1; i < num_levels; i++)
offsets[i] = offsets[i-1] + num_points[i-1];
}
GaussHermite::GaussHermite()
: OneDPrecalcQuadrature(gh_num_levels, gh_num_points, gh_weights, gh_points)
{
}
GaussLegendre::GaussLegendre()
: OneDPrecalcQuadrature(gl_num_levels, gl_num_points, gl_weights, gl_points)
{
}

View File

@ -1,63 +0,0 @@
@q $Id: quadrature.cweb 431 2005-08-16 15:41:01Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@ This is {\tt quadrature.cpp} file.
@c
#include "quadrature.h"
#include "precalc_quadrature.dat"
#include <cmath>
@<|OneDPrecalcQuadrature::calcOffsets| code@>;
@<|GaussHermite| constructor code@>;
@<|GaussLegendre| constructor code@>;
@<|NormalICDF| get code@>;
@
@<|OneDPrecalcQuadrature::calcOffsets| code@>=
void OneDPrecalcQuadrature::calcOffsets()
{
offsets[0] = 0;
for (int i = 1; i < num_levels; i++)
offsets[i] = offsets[i-1] + num_points[i-1];
}
@
@<|GaussHermite| constructor code@>=
GaussHermite::GaussHermite()
: OneDPrecalcQuadrature(gh_num_levels, gh_num_points, gh_weights, gh_points)@+ {}
@
@<|GaussLegendre| constructor code@>=
GaussLegendre::GaussLegendre()
: OneDPrecalcQuadrature(gl_num_levels, gl_num_points, gl_weights, gl_points)@+ {}
@ Here we transform a draw from univariate $\langle 0,1\rangle$ to the
draw from Gaussina $N(0,1)$. This is done by a table lookup, the table
is given by |normal_icdf_step|, |normal_icfd_data|, |normal_icdf_num|,
and a number |normal_icdf_end|. In order to avoid wrong tails for lookups close
to zero or one, we rescale input |x| by $(1-2*(1-end))=2*end-1$.
@<|NormalICDF| get code@>=
double NormalICDF::get(double x)
{
double xx = (2*normal_icdf_end-1)*std::abs(x-0.5);
int i = (int)floor(xx/normal_icdf_step);
double xx1 = normal_icdf_step*i;
double yy1 = normal_icdf_data[i];
double y;
if (i < normal_icdf_num-1) {
double yy2 = normal_icdf_data[i+1];
y = yy1 + (yy2-yy1)*(xx-xx1)/normal_icdf_step;
} else { // this should never happen
y = yy1;
}
if (x > 0.5)
return y;
else
return -y;
}
@ End of {\tt quadrature.cpp} file

View File

@ -0,0 +1,329 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
// Quadrature.
/* This file defines an interface for one dimensional (non-nested) quadrature
OneDQuadrature, and a parent for all multi-dimensional quadratures. This
parent class Quadrature presents a general concept of quadrature, this is
N
f(x)dx wx
¹
The class Quadrature just declares this concept. The concept is implemented
by class QuadratureImpl which paralelizes the summation. All implementations
therefore wishing to use the parallel implementation should inherit from
QuadratureImpl and integration is done.
The integration concept relies on a point iterator, which goes through all
x and w for i=1,,N. All the iterators must be able to go through only a
portion of the set i=1,,N. This enables us to implement paralelism, for two
threads for example, one iterator goes from the beginning to the
(approximately) half, and the other goes from the half to the end.
Besides this concept of the general quadrature, this file defines also one
dimensional quadrature, which is basically a scheme of points and weights
for different levels. The class OneDQuadrature is a parent of all such
objects, the classes GaussHermite and GaussLegendre are specific
implementations for Gauss-Hermite and Gauss-Legendre quadratures resp. */
#ifndef QUADRATURE_H
#define QUADRATURE_H
#include <iostream>
#include <fstream>
#include <iomanip>
#include "vector_function.hh"
#include "int_sequence.hh"
#include "sthread.hh"
/* This pure virtual class represents a concept of one-dimensional (non-nested)
quadrature. So, one dimensional quadrature must return number of levels,
number of points in a given level, and then a point and a weight in a given
level and given order. */
class OneDQuadrature
{
public:
virtual ~OneDQuadrature() = default;
virtual int numLevels() const = 0;
virtual int numPoints(int level) const = 0;
virtual double point(int level, int i) const = 0;
virtual double weight(int lelel, int i) const = 0;
};
/* This is a general concept of multidimensional quadrature. at this general
level, we maintain only a dimension, and declare virtual functions for
integration. The function take two forms; first takes a constant
VectorFunction as an argument, creates locally VectorFunctionSet and do
calculation, second one takes as an argument VectorFunctionSet.
Part of the interface is a method returning a number of evaluations for a
specific level. Note two things: this assumes that the number of evaluations
is known apriori and thus it is not applicable for adaptive quadratures,
second for Monte Carlo type of quadrature, the level is a number of
evaluations. */
class Quadrature
{
protected:
int dim;
public:
Quadrature(int d) : dim(d)
{
}
virtual ~Quadrature() = default;
int
dimen() const
{
return dim;
}
virtual void integrate(const VectorFunction &func, int level,
int tn, Vector &out) const = 0;
virtual void integrate(VectorFunctionSet &fs, int level, Vector &out) const = 0;
virtual int numEvals(int level) const = 0;
};
/* This is just an integration worker, which works over a given QuadratureImpl.
It also needs the function, level, a specification of the subgroup of
points, and output vector.
See QuadratureImpl class declaration for details. */
template <typename _Tpit>
class QuadratureImpl;
template <typename _Tpit>
class IntegrationWorker : public sthread::detach_thread
{
const QuadratureImpl<_Tpit> &quad;
VectorFunction &func;
int level;
int ti;
int tn;
Vector &outvec;
public:
IntegrationWorker(const QuadratureImpl<_Tpit> &q, VectorFunction &f, int l,
int tii, int tnn, Vector &out)
: quad(q), func(f), level(l), ti(tii), tn(tnn), outvec(out)
{
}
/* This integrates the given portion of the integral. We obtain first and
last iterators for the portion (beg and end). Then we iterate through
the portion. and finally we add the intermediate result to the result
outvec.
This method just everything up as it is coming. This might be imply large
numerical errors, perhaps in future something smarter should be implemented. */
void
operator()(std::mutex &mut) override
{
_Tpit beg = quad.begin(ti, tn, level);
_Tpit end = quad.begin(ti+1, tn, level);
Vector tmpall(outvec.length());
tmpall.zeros();
Vector tmp(outvec.length());
/* Note that since beg came from begin(), it has empty signal and first
evaluation gets no signal */
for (_Tpit run = beg; run != end; ++run)
{
func.eval(run.point(), run.signal(), tmp);
tmpall.add(run.weight(), tmp);
}
{
std::unique_lock<std::mutex> lk{mut};
outvec.add(1.0, tmpall);
}
}
};
/* This is the class which implements the integration. The class is templated
by the iterator type. We declare a method begin() returning an iterator to
the beginnning of the ti-th portion out of total tn portions for a given
level.
In addition, we define a method which saves all the points to a given file.
Only for debugging purposes. */
template <typename _Tpit>
class QuadratureImpl : public Quadrature
{
friend class IntegrationWorker<_Tpit>;
public:
QuadratureImpl(int d) : Quadrature(d)
{
}
/* Just fill a thread group with workes and run it. */
void
integrate(VectorFunctionSet &fs, int level, Vector &out) const override
{
// TODO: out.length()==func.outdim()
// TODO: dim == func.indim()
out.zeros();
sthread::detach_thread_group gr;
for (int ti = 0; ti < fs.getNum(); ti++)
gr.insert(std::make_unique<IntegrationWorker<_Tpit>>(*this, fs.getFunc(ti),
level, ti, fs.getNum(), out));
gr.run();
}
void
integrate(const VectorFunction &func,
int level, int tn, Vector &out) const override
{
VectorFunctionSet fs(func, tn);
integrate(fs, level, out);
}
/* Just for debugging. */
void
savePoints(const std::string &fname, int level) const
{
std::ofstream fd{fname, std::ios::out | std::ios::trunc};
if (fd.fail())
{
// TODO: raise
std::cerr << "Cannot open file " << fname << " for writing." << std::endl;
exit(EXIT_FAILURE);
}
_Tpit beg = begin(0, 1, level);
_Tpit end = begin(1, 1, level);
fd << std::setprecision(12);
for (_Tpit run = beg; run != end; ++run)
{
fd << std::setw(16) << run.weight();
for (int i = 0; i < dimen(); i++)
fd << '\t' << std::setw(16) << run.point()[i];
fd << std::endl;
}
fd.close();
}
_Tpit
start(int level) const
{
return begin(0, 1, level);
}
_Tpit
end(int level) const
{
return begin(1, 1, level);
}
protected:
virtual _Tpit begin(int ti, int tn, int level) const = 0;
};
/* This is only an interface to a precalculated data in file
precalc_quadrature.hh which is basically C coded static data. It implements
OneDQuadrature. The data file is supposed to define the following data:
number of levels, array of number of points at each level, an array of
weights and array of points. The both latter array store data level by
level. An offset for a specific level is stored in offsets integer
sequence.
The implementing subclasses just fill the necessary data from the file, the
rest is calculated here. */
class OneDPrecalcQuadrature : public OneDQuadrature
{
int num_levels;
const int *num_points;
const double *weights;
const double *points;
IntSequence offsets;
public:
OneDPrecalcQuadrature(int nlevels, const int *npoints,
const double *wts, const double *pts)
: num_levels(nlevels), num_points(npoints),
weights(wts), points(pts), offsets(num_levels)
{
calcOffsets();
}
~OneDPrecalcQuadrature() override = default;
int
numLevels() const override
{
return num_levels;
}
int
numPoints(int level) const override
{
return num_points[level-1];
}
double
point(int level, int i) const override
{
return points[offsets[level-1]+i];
}
double
weight(int level, int i) const override
{
return weights[offsets[level-1]+i];
}
protected:
void calcOffsets();
};
/* Just precalculated Gauss-Hermite quadrature. This quadrature integrates
exactly integrals
+
xe^{x²}dx
for level k.
Note that if pluging this one-dimensional quadrature to product or Smolyak
rule in order to integrate a function f through normally distributed inputs,
one has to wrap f to GaussConverterFunction and apply the product or Smolyak
rule to the new function.
Check precalc_quadrature.hh for available levels. */
class GaussHermite : public OneDPrecalcQuadrature
{
public:
GaussHermite();
};
/* Just precalculated Gauss-Legendre quadrature. This quadrature integrates
exactly integrals
xdx
for level k.
Check precalc_quadrature.hh for available levels. */
class GaussLegendre : public OneDPrecalcQuadrature
{
public:
GaussLegendre();
};
#endif

View File

@ -1,311 +0,0 @@
@q $Id: quadrature.hweb 2269 2008-11-23 14:33:22Z michel $ @>
@q Copyright 2005, Ondra Kamenik @>
@*2 Quadrature. This is {\tt quadrature.h} file
This file defines an interface for one dimensional (non-nested) quadrature
|OneDQuadrature|, and a parent for all multi-dimensional
quadratures. This parent class |Quadrature| presents a general concept of
quadrature, this is
$$\int f(x){\rm d}x \approx\sum_{i=1}^N w_ix_i$$
The class |Quadrature| just declares this concept. The concept is
implemented by class |QuadratureImpl| which paralelizes the
summation. All implementations therefore wishing to use the parallel
implementation should inherit from |QuadratureImpl| and integration is
done.
The integration concept relies on a point iterator, which goes through
all $x_i$ and $w_i$ for $i=1,\ldots,N$. All the iterators must be able
to go through only a portion of the set $i=1,\ldots,N$. This enables
us to implement paralelism, for two threads for example, one iterator
goes from the beginning to the (approximately) half, and the other
goes from the half to the end.
Besides this concept of the general quadrature, this file defines also
one dimensional quadrature, which is basically a scheme of points and
weights for different levels. The class |OneDQuadrature| is a parent
of all such objects, the classes |GaussHermite| and |GaussLegendre|
are specific implementations for Gauss--Hermite and Gauss--Legendre
quadratures resp.
@s OneDQuadrature int
@s Quadrature int
@s IntegrationWorker int
@s QuadratureImpl int
@s OneDPrecalcQuadrature int
@s GaussHermite int
@s GaussLegendre int
@s NormalICDF int
@s _Tpit int
@c
#ifndef QUADRATURE_H
#define QUADRATURE_H
#include <cstdlib>
#include "vector_function.h"
#include "int_sequence.h"
#include "sthread.h"
@<|OneDQuadrature| class declaration@>;
@<|Quadrature| class declaration@>;
@<|IntegrationWorker| class declaration@>;
@<|QuadratureImpl| class declaration@>;
@<|OneDPrecalcQuadrature| class declaration@>;
@<|GaussHermite| class declaration@>;
@<|GaussLegendre| class declaration@>;
@<|NormalICDF| class declaration@>;
#endif
@ This pure virtual class represents a concept of one-dimensional
(non-nested) quadrature. So, one dimensional quadrature must return
number of levels, number of points in a given level, and then a point
and a weight in a given level and given order.
@<|OneDQuadrature| class declaration@>=
class OneDQuadrature {
public:@;
virtual ~OneDQuadrature()@+ {}
virtual int numLevels() const =0;
virtual int numPoints(int level) const =0;
virtual double point(int level, int i) const =0;
virtual double weight(int lelel, int i) const =0;
};
@ This is a general concept of multidimensional quadrature. at this
general level, we maintain only a dimension, and declare virtual
functions for integration. The function take two forms; first takes a
constant |VectorFunction| as an argument, creates locally
|VectorFunctionSet| and do calculation, second one takes as an
argument |VectorFunctionSet|.
Part of the interface is a method returning a number of evaluations
for a specific level. Note two things: this assumes that the number of
evaluations is known apriori and thus it is not applicable for
adaptive quadratures, second for Monte Carlo type of quadrature, the
level is a number of evaluations.
@<|Quadrature| class declaration@>=
class Quadrature {
protected:@;
int dim;
public:@;
Quadrature(int d) : dim(d)@+ {}
virtual ~Quadrature()@+ {}
int dimen() const
{@+ return dim;@+}
virtual void integrate(const VectorFunction& func, int level,
int tn, Vector& out) const =0;
virtual void integrate(VectorFunctionSet& fs, int level, Vector& out) const =0;
virtual int numEvals(int level) const =0;
};
@ This is just an integration worker, which works over a given
|QuadratureImpl|. It also needs the function, level, a specification
of the subgroup of points, and output vector.
See |@<|QuadratureImpl| class declaration@>| for details.
@<|IntegrationWorker| class declaration@>=
template <typename _Tpit>
class QuadratureImpl;
template <typename _Tpit>
class IntegrationWorker : public THREAD {
const QuadratureImpl<_Tpit>& quad;
VectorFunction& func;
int level;
int ti;
int tn;
Vector& outvec;
public:@;
IntegrationWorker(const QuadratureImpl<_Tpit>& q, VectorFunction& f, int l,
int tii, int tnn, Vector& out)
: quad(q), func(f), level(l), ti(tii), tn(tnn), outvec(out) @+{}
@<|IntegrationWorker::operator()()| code@>;
};
@ This integrates the given portion of the integral. We obtain first
and last iterators for the portion (|beg| and |end|). Then we iterate
through the portion. and finally we add the intermediate result to the
result |outvec|.
This method just everything up as it is coming. This might be imply
large numerical errors, perhaps in future I will implement something
smarter.
@<|IntegrationWorker::operator()()| code@>=
void operator()() {
_Tpit beg = quad.begin(ti, tn, level);
_Tpit end = quad.begin(ti+1, tn, level);
Vector tmpall(outvec.length());
tmpall.zeros();
Vector tmp(outvec.length());
// note that since beg came from begin, it has empty signal
// and first evaluation gets no signal
for (_Tpit run = beg; run != end; ++run) {
func.eval(run.point(), run.signal(), tmp);
tmpall.add(run.weight(), tmp);
}
{
SYNCHRO@, syn(&outvec, "IntegrationWorker");
outvec.add(1.0, tmpall);
}
}
@ This is the class which implements the integration. The class is
templated by the iterator type. We declare a method |begin| returning
an iterator to the beginnning of the |ti|-th portion out of total |tn|
portions for a given level.
In addition, we define a method which saves all the points to a given
file. Only for debugging purposes.
@<|QuadratureImpl| class declaration@>=
template <typename _Tpit>
class QuadratureImpl : public Quadrature {
friend class IntegrationWorker<_Tpit>;
public:@;
QuadratureImpl(int d) : Quadrature(d)@+ {}
@<|QuadratureImpl::integrate| code@>;
void integrate(const VectorFunction& func,
int level, int tn, Vector& out) const {
VectorFunctionSet fs(func, tn);
integrate(fs, level, out);
}
@<|Quadrature::savePoints| code@>;
_Tpit start(int level) const
{@+ return begin(0,1,level);@+}
_Tpit end(int level) const
{@+ return begin(1,1,level);@+}
protected:@;
virtual _Tpit begin(int ti, int tn, int level) const =0;
};
@ Just fill a thread group with workes and run it.
@<|QuadratureImpl::integrate| code@>=
void integrate(VectorFunctionSet& fs, int level, Vector& out) const {
// todo: out.length()==func.outdim()
// todo: dim == func.indim()
out.zeros();
THREAD_GROUP@, gr;
for (int ti = 0; ti < fs.getNum(); ti++) {
gr.insert(new IntegrationWorker<_Tpit>(*this, fs.getFunc(ti),
level, ti, fs.getNum(), out));
}
gr.run();
}
@ Just for debugging.
@<|Quadrature::savePoints| code@>=
void savePoints(const char* fname, int level) const
{
FILE* fd;
if (NULL==(fd = fopen(fname,"w"))) {
// todo: raise
fprintf(stderr, "Cannot open file %s for writing.\n", fname);
exit(1);
}
_Tpit beg = begin(0,1,level);
_Tpit end = begin(1,1,level);
for (_Tpit run = beg; run != end; ++run) {
fprintf(fd, "%16.12g", run.weight());
for (int i = 0; i < dimen(); i++)
fprintf(fd, "\t%16.12g", run.point()[i]);
fprintf(fd, "\n");
}
fclose(fd);
}
@ This is only an interface to a precalculated data in file {\tt
precalc\_quadrature.dat} which is basically C coded static data. It
implements |OneDQuadrature|. The data file is supposed to define the
following data: number of levels, array of number of points at each
level, an array of weights and array of points. The both latter array
store data level by level. An offset for a specific level is stored in
|offsets| integer sequence.
The implementing subclasses just fill the necessary data from the
file, the rest is calculated here.
@<|OneDPrecalcQuadrature| class declaration@>=
class OneDPrecalcQuadrature : public OneDQuadrature {
int num_levels;
const int* num_points;
const double* weights;
const double* points;
IntSequence offsets;
public:@;
OneDPrecalcQuadrature(int nlevels, const int* npoints,
const double* wts, const double* pts)
: num_levels(nlevels), num_points(npoints),
weights(wts), points(pts), offsets(num_levels)
{@+ calcOffsets();@+}
virtual ~OneDPrecalcQuadrature()@+ {}
int numLevels() const
{@+ return num_levels;@+}
int numPoints(int level) const
{@+ return num_points[level-1];@+}
double point(int level, int i) const
{@+ return points[offsets[level-1]+i];@+}
double weight(int level, int i) const
{@+ return weights[offsets[level-1]+i];@+}
protected:@;
void calcOffsets();
};
@ Just precalculated Gauss--Hermite quadrature. This quadrature integrates exactly integrals
$$\int_{-\infty}^{\infty} x^ke^{-x^2}{\rm d}x$$
for level $k$.
Note that if pluging this one-dimensional quadrature to product or
Smolyak rule in order to integrate a function $f$ through normally
distributed inputs, one has to wrap $f$ to
|GaussConverterFunction| and apply the product or Smolyak rule to the
new function.
Check {\tt precalc\_quadrature.dat} for available levels.
@<|GaussHermite| class declaration@>=
class GaussHermite : public OneDPrecalcQuadrature {
public:@;
GaussHermite();
};
@ Just precalculated Gauss--Legendre quadrature. This quadrature integrates exactly integrals
$$\int_0^1x^k{\rm d}x$$
for level $k$.
Check {\tt precalc\_quadrature.dat} for available levels.
@<|GaussLegendre| class declaration@>=
class GaussLegendre : public OneDPrecalcQuadrature {
public:@;
GaussLegendre();
};
@ This is just an inverse cummulative density function of normal
distribution. Its only method |get| returns for a given number
$x\in(0,1)$ a number $y$ such that $P(z<y)=x$, where the probability
is taken over normal distribution $N(0,1)$.
Currently, the implementation is done by a table lookup which implies
that the tails had to be chopped off. This further implies that Monte
Carlo quadratures using this transformation to draw points from
multidimensional $N(0,I)$ fail to integrate with satisfactory
precision polynomial functions, for which the tails matter.
@<|NormalICDF| class declaration@>=
class NormalICDF {
public:@;
static double get(double x);
};
@ End of {\tt quadrature.h} file

View File

@ -0,0 +1,213 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
#include "quasi_mcarlo.hh"
#include <cmath>
#include <iostream>
#include <iomanip>
#include <array>
/* Here in the constructor, we have to calculate a maximum length of coeff
array for a given base and given maximum maxn. After allocation, we
calculate the coefficients. */
RadicalInverse::RadicalInverse(int n, int b, int mxn)
: num(n), base(b), maxn(mxn),
coeff(static_cast<int>(floor(log(static_cast<double>(maxn))/log(static_cast<double>(b)))+2), 0)
{
int nr = num;
j = -1;
do
{
j++;
coeff[j] = nr % base;
nr = nr / base;
}
while (nr > 0);
}
/* This evaluates the radical inverse. If there was no permutation, we have to
calculate:
c c c
+ + +
b b² bʲ¹
which is evaluated as:
c 1 c 1 c 1 c
· + · + · +
b b b b b b b
Now with permutation π, we have:
π(c) 1 π(c) 1 π(c) 1 π(c)
· + · + · +
b b b b b b b
*/
double
RadicalInverse::eval(const PermutationScheme &p) const
{
double res = 0;
for (int i = j; i >= 0; i--)
{
int cper = p.permute(i, base, coeff[i]);
res = (cper + res)/base;
}
return res;
}
/* We just add 1 to the lowest coefficient and check for overflow with respect
to the base. */
void
RadicalInverse::increase()
{
// TODO: raise if num+1 > maxn
num++;
int i = 0;
coeff[i]++;
while (coeff[i] == base)
{
coeff[i] = 0;
coeff[++i]++;
}
if (i > j)
j = i;
}
/* Debug print. */
void
RadicalInverse::print() const
{
std::cout << "n=" << num << " b=" << base << " c=";
coeff.print();
}
/* Here we have the first 170 primes. This means that we are not able to
integrate dimensions greater than 170. */
std::array<int, 170> HaltonSequence::primes = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013
};
/* This takes first dim primes and constructs dim radical inverses and
calls eval(). */
HaltonSequence::HaltonSequence(int n, int mxn, int dim, const PermutationScheme &p)
: num(n), maxn(mxn), per(p), pt(dim)
{
// TODO: raise if dim > num_primes
// TODO: raise if n > mxn
for (int i = 0; i < dim; i++)
ri.emplace_back(num, primes[i], maxn);
eval();
}
/* This calls RadicalInverse::increase() for all radical inverses and calls
eval(). */
void
HaltonSequence::increase()
{
for (auto & i : ri)
i.increase();
num++;
if (num <= maxn)
eval();
}
/* This sets point pt to radical inverse evaluations in each dimension. */
void
HaltonSequence::eval()
{
for (unsigned int i = 0; i < ri.size(); i++)
pt[i] = ri[i].eval(per);
}
/* Debug print. */
void
HaltonSequence::print() const
{
auto ff = std::cout.flags();
for (const auto & i : ri)
i.print();
std::cout << "point=[ "
<< std::fixed << std::setprecision(6);
for (unsigned int i = 0; i < ri.size(); i++)
std::cout << std::setw(7) << pt[i] << ' ';
std::cout << ']' << std::endl;
std::cout.flags(ff);
}
qmcpit::qmcpit(const QMCSpecification &s, int n)
: spec(s), halton{n, s.level(), s.dimen(), s.getPerScheme()},
sig{s.dimen()}
{
}
bool
qmcpit::operator==(const qmcpit &qpit) const
{
return &spec == &qpit.spec && halton.getNum() == qpit.halton.getNum();
}
qmcpit &
qmcpit::operator++()
{
halton.increase();
return *this;
}
double
qmcpit::weight() const
{
return 1.0/spec.level();
}
int
WarnockPerScheme::permute(int i, int base, int c) const
{
return (c+i) % base;
}
int
ReversePerScheme::permute(int i, int base, int c) const
{
return (base-c) % base;
}

View File

@ -1,341 +0,0 @@
@q $Id: quasi_mcarlo.cweb 431 2005-08-16 15:41:01Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@ This is {\tt quasi\_mcarlo.cpp} file.
@c
#include "quasi_mcarlo.h"
#include <cmath>
@<|RadicalInverse| constructor code@>;
@<|RadicalInverse::eval| code@>;
@<|RadicalInverse::increase| code@>;
@<|RadicalInverse::print| code@>;
@<|HaltonSequence| static data@>;
@<|HaltonSequence| constructor code@>;
@<|HaltonSequence::operator=| code@>;
@<|HaltonSequence::increase| code@>;
@<|HaltonSequence::eval| code@>;
@<|HaltonSequence::print| code@>;
@<|qmcpit| empty constructor code@>;
@<|qmcpit| regular constructor code@>;
@<|qmcpit| copy constructor code@>;
@<|qmcpit| destructor@>;
@<|qmcpit::operator==| code@>;
@<|qmcpit::operator=| code@>;
@<|qmcpit::operator++| code@>;
@<|qmcpit::weight| code@>;
@<|qmcnpit| empty constructor code@>;
@<|qmcnpit| regular constructor code@>;
@<|qmcnpit| copy constructor code@>;
@<|qmcnpit| destructor@>;
@<|qmcnpit::operator=| code@>;
@<|qmcnpit::operator++| code@>;
@<|WarnockPerScheme::permute| code@>;
@<|ReversePerScheme::permute| code@>;
@ Here in the constructor, we have to calculate a maximum length of
|coeff| array for a given |base| and given maximum |maxn|. After
allocation, we calculate the coefficients.
@<|RadicalInverse| constructor code@>=
RadicalInverse::RadicalInverse(int n, int b, int mxn)
: num(n), base(b), maxn(mxn),
coeff((int)(floor(log((double)maxn)/log((double)b))+2), 0)
{
int nr = num;
j = -1;
do {
j++;
coeff[j] = nr % base;
nr = nr / base;
} while (nr > 0);
}
@ This evaluates the radical inverse. If there was no permutation, we have to calculate
$$
{c_0\over b}+{c_1\over b^2}+\ldots+{c_j\over b^{j+1}}
$$
which is evaluated as
$$
\left(\ldots\left(\left({c_j\over b}\cdot{1\over b}+{c_{j-1}\over b}\right)
\cdot{1\over b}+{c_{j-2}\over b}\right)
\ldots\right)\cdot{1\over b}+{c_0\over b}
$$
Now with permutation $\pi$, we have
$$
\left(\ldots\left(\left({\pi(c_j)\over b}\cdot{1\over b}+
{\pi(c_{j-1})\over b}\right)\cdot{1\over b}+
{\pi(c_{j-2})\over b}\right)
\ldots\right)\cdot{1\over b}+{\pi(c_0)\over b}
$$
@<|RadicalInverse::eval| code@>=
double RadicalInverse::eval(const PermutationScheme& p) const
{
double res = 0;
for (int i = j; i >= 0; i--) {
int cper = p.permute(i, base, coeff[i]);
res = (cper + res)/base;
}
return res;
}
@ We just add 1 to the lowest coefficient and check for overflow with respect to the base.
@<|RadicalInverse::increase| code@>=
void RadicalInverse::increase()
{
// todo: raise if |num+1 > maxn|
num++;
int i = 0;
coeff[i]++;
while (coeff[i] == base) {
coeff[i] = 0;
coeff[++i]++;
}
if (i > j)
j = i;
}
@ Debug print.
@<|RadicalInverse::print| code@>=
void RadicalInverse::print() const
{
printf("n=%d b=%d c=", num, base);
coeff.print();
}
@ Here we have the first 170 primes. This means that we are not able
to integrate dimensions greater than 170.
@<|HaltonSequence| static data@>=
int HaltonSequence::num_primes = 170;
int HaltonSequence::primes[] = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013
};
@ This takes first |dim| primes and constructs |dim| radical inverses
and calls |eval|.
@<|HaltonSequence| constructor code@>=
HaltonSequence::HaltonSequence(int n, int mxn, int dim, const PermutationScheme& p)
: num(n), maxn(mxn), per(p), pt(dim)
{
// todo: raise if |dim > num_primes|
// todo: raise if |n > mxn|
for (int i = 0; i < dim; i++)
ri.push_back(RadicalInverse(num, primes[i], maxn));
eval();
}
@
@<|HaltonSequence::operator=| code@>=
const HaltonSequence& HaltonSequence::operator=(const HaltonSequence& hs)
{
num = hs.num;
maxn = hs.maxn;
ri.clear();
for (unsigned int i = 0; i < hs.ri.size(); i++)
ri.push_back(RadicalInverse(hs.ri[i]));
pt = hs.pt;
return *this;
}
@ This calls |RadicalInverse::increase| for all radical inverses and
calls |eval|.
@<|HaltonSequence::increase| code@>=
void HaltonSequence::increase()
{
for (unsigned int i = 0; i < ri.size(); i++)
ri[i].increase();
num++;
if (num <= maxn)
eval();
}
@ This sets point |pt| to radical inverse evaluations in each dimension.
@<|HaltonSequence::eval| code@>=
void HaltonSequence::eval()
{
for (unsigned int i = 0; i < ri.size(); i++)
pt[i] = ri[i].eval(per);
}
@ Debug print.
@<|HaltonSequence::print| code@>=
void HaltonSequence::print() const
{
for (unsigned int i = 0; i < ri.size(); i++)
ri[i].print();
printf("point=[ ");
for (unsigned int i = 0; i < ri.size(); i++)
printf("%7.6f ", pt[i]);
printf("]\n");
}
@
@<|qmcpit| empty constructor code@>=
qmcpit::qmcpit()
: spec(NULL), halton(NULL), sig(NULL)@+ {}
@
@<|qmcpit| regular constructor code@>=
qmcpit::qmcpit(const QMCSpecification& s, int n)
: spec(&s), halton(new HaltonSequence(n, s.level(), s.dimen(), s.getPerScheme())),
sig(new ParameterSignal(s.dimen()))
{
}
@
@<|qmcpit| copy constructor code@>=
qmcpit::qmcpit(const qmcpit& qpit)
: spec(qpit.spec), halton(NULL), sig(NULL)
{
if (qpit.halton)
halton = new HaltonSequence(*(qpit.halton));
if (qpit.sig)
sig = new ParameterSignal(qpit.spec->dimen());
}
@
@<|qmcpit| destructor@>=
qmcpit::~qmcpit()
{
if (halton)
delete halton;
if (sig)
delete sig;
}
@
@<|qmcpit::operator==| code@>=
bool qmcpit::operator==(const qmcpit& qpit) const
{
return (spec == qpit.spec) &&
((halton == NULL && qpit.halton == NULL) ||
(halton != NULL && qpit.halton != NULL && halton->getNum() == qpit.halton->getNum()));
}
@
@<|qmcpit::operator=| code@>=
const qmcpit& qmcpit::operator=(const qmcpit& qpit)
{
spec = qpit.spec;
if (halton)
delete halton;
if (qpit.halton)
halton = new HaltonSequence(*(qpit.halton));
else
halton = NULL;
return *this;
}
@
@<|qmcpit::operator++| code@>=
qmcpit& qmcpit::operator++()
{
// todo: raise if |halton == null || qmcq == NULL|
halton->increase();
return *this;
}
@
@<|qmcpit::weight| code@>=
double qmcpit::weight() const
{
return 1.0/spec->level();
}
@
@<|qmcnpit| empty constructor code@>=
qmcnpit::qmcnpit()
: qmcpit(), pnt(NULL)@+ {}
@
@<|qmcnpit| regular constructor code@>=
qmcnpit::qmcnpit(const QMCSpecification& s, int n)
: qmcpit(s, n), pnt(new Vector(s.dimen()))
{
}
@
@<|qmcnpit| copy constructor code@>=
qmcnpit::qmcnpit(const qmcnpit& qpit)
: qmcpit(qpit), pnt(NULL)
{
if (qpit.pnt)
pnt = new Vector(*(qpit.pnt));
}
@
@<|qmcnpit| destructor@>=
qmcnpit::~qmcnpit()
{
if (pnt)
delete pnt;
}
@
@<|qmcnpit::operator=| code@>=
const qmcnpit& qmcnpit::operator=(const qmcnpit& qpit)
{
qmcpit::operator=(qpit);
if (pnt)
delete pnt;
if (qpit.pnt)
pnt = new Vector(*(qpit.pnt));
else
pnt = NULL;
return *this;
}
@ Here we inccrease a point in Halton sequence ant then store images
of the points in |NormalICDF| function.
@<|qmcnpit::operator++| code@>=
qmcnpit& qmcnpit::operator++()
{
qmcpit::operator++();
for (int i = 0; i < halton->point().length(); i++)
(*pnt)[i] = NormalICDF::get(halton->point()[i]);
return *this;
}
@ Clear from code.
@<|WarnockPerScheme::permute| code@>=
int WarnockPerScheme::permute(int i, int base, int c) const
{
return (c+i) % base;
}
@ Clear from code.
@<|ReversePerScheme::permute| code@>=
int ReversePerScheme::permute(int i, int base, int c) const
{
return (base-c) % base;
}
@ End of {\tt quasi\_mcarlo.cpp} file.

View File

@ -0,0 +1,256 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
// Quasi Monte Carlo quadrature.
/* This defines quasi Monte Carlo quadratures for cube and for a function
multiplied by normal density. The quadrature for a cube is named
QMCarloCubeQuadrature and integrates:
f(x)dx
[0,1]
The quadrature for a function of normally distributed parameters is named
QMCarloNormalQuadrature and integrates:
1
f(x)e^{½xx}dx
{(2π)} [,+]
For a cube we define qmcpit as iterator of QMCarloCubeQuadrature, and for
the normal density multiplied function we define qmcnpit as iterator of
QMCarloNormalQuadrature.
The quasi Monte Carlo method generates low discrepancy points with equal
weights. The one dimensional low discrepancy sequences are generated by
RadicalInverse class, the sequences are combined for higher dimensions by
HaltonSequence class. The Halton sequence can use a permutation scheme;
PermutattionScheme is an abstract class for all permutaton schemes. We have
three implementations: WarnockPerScheme, ReversePerScheme, and
IdentityPerScheme. */
#ifndef QUASI_MCARLO_H
#define QUASI_MCARLO_H
#include "int_sequence.hh"
#include "quadrature.hh"
#include "Vector.hh"
#include <vector>
/* This abstract class declares permute() method which permutes coefficient c
having index of i fro the base base and returns the permuted coefficient
which must be in 0,,base1. */
class PermutationScheme
{
public:
PermutationScheme() = default;
virtual ~PermutationScheme() = default;
virtual int permute(int i, int base, int c) const = 0;
};
/* This class represents an integer number num as c₀+c₁b+c₂b²+…+cⱼbʲ, where b
is base and c,,c is stored in coeff. The size of IntSequence coeff
does not grow with growing num, but is fixed from the very beginning and
is set according to supplied maximum maxn.
The basic method is eval() which evaluates the RadicalInverse with a given
permutation scheme and returns the point, and increase() which increases
num and recalculates the coefficients. */
class RadicalInverse
{
int num;
int base;
int maxn;
int j;
IntSequence coeff;
public:
RadicalInverse(int n, int b, int mxn);
RadicalInverse(const RadicalInverse &ri) = default;
RadicalInverse &operator=(const RadicalInverse &radi) = default;
double eval(const PermutationScheme &p) const;
void increase();
void print() const;
};
/* This is a vector of RadicalInverses, each RadicalInverse has a different
prime as its base. The static members primes and num_primes define a
precalculated array of primes. The increase() method of the class increases
indices in all RadicalInverses and sets point pt to contain the points in
each dimension. */
class HaltonSequence
{
private:
static std::array<int, 170> primes;
protected:
int num;
int maxn;
std::vector<RadicalInverse> ri;
const PermutationScheme &per;
Vector pt;
public:
HaltonSequence(int n, int mxn, int dim, const PermutationScheme &p);
HaltonSequence(const HaltonSequence &hs) = default;
HaltonSequence &operator=(const HaltonSequence &hs) = delete;
void increase();
const Vector &
point() const
{
return pt;
}
const int
getNum() const
{
return num;
}
void print() const;
protected:
void eval();
};
/* This is a specification of quasi Monte Carlo quadrature. It consists of
dimension dim, number of points (or level) lev, and the permutation
scheme. This class is common to all quasi Monte Carlo classes. */
class QMCSpecification
{
protected:
int dim;
int lev;
const PermutationScheme &per_scheme;
public:
QMCSpecification(int d, int l, const PermutationScheme &p)
: dim(d), lev(l), per_scheme(p)
{
}
virtual ~QMCSpecification() = default;
int
dimen() const
{
return dim;
}
int
level() const
{
return lev;
}
const PermutationScheme &
getPerScheme() const
{
return per_scheme;
}
};
/* This is an iterator for quasi Monte Carlo over a cube QMCarloCubeQuadrature.
The iterator maintains HaltonSequence of the same dimension as given by the
specification. An iterator can be constructed from a given number n, or by
a copy constructor. */
class qmcpit
{
protected:
const QMCSpecification &spec;
HaltonSequence halton;
ParameterSignal sig;
public:
qmcpit(const QMCSpecification &s, int n);
qmcpit(const qmcpit &qpit) = default;
virtual ~qmcpit() = default;
bool operator==(const qmcpit &qpit) const;
bool
operator!=(const qmcpit &qpit) const
{
return !operator==(qpit);
}
qmcpit &operator=(const qmcpit &qpit) = delete;
qmcpit &operator++();
const ParameterSignal &
signal() const
{
return sig;
}
const Vector &
point() const
{
return halton.point();
}
double weight() const;
void
print() const
{
halton.print();
}
};
/* This is an easy declaration of quasi Monte Carlo quadrature for a cube.
Everything important has been done in its iterator qmcpit, so we only
inherit from general Quadrature and reimplement begin() and numEvals(). */
class QMCarloCubeQuadrature : public QuadratureImpl<qmcpit>, public QMCSpecification
{
public:
QMCarloCubeQuadrature(int d, int l, const PermutationScheme &p)
: QuadratureImpl<qmcpit>(d), QMCSpecification(d, l, p)
{
}
~QMCarloCubeQuadrature() override = default;
int
numEvals(int l) const override
{
return l;
}
protected:
qmcpit
begin(int ti, int tn, int lev) const override
{
return qmcpit(*this, ti*level()/tn + 1);
}
};
/* Declares Warnock permutation scheme. */
class WarnockPerScheme : public PermutationScheme
{
public:
int permute(int i, int base, int c) const override;
};
/* Declares reverse permutation scheme. */
class ReversePerScheme : public PermutationScheme
{
public:
int permute(int i, int base, int c) const override;
};
/* Declares no permutation (identity) scheme. */
class IdentityPerScheme : public PermutationScheme
{
public:
int
permute(int i, int base, int c) const override
{
return c;
}
};
#endif

View File

@ -1,286 +0,0 @@
@q $Id: quasi_mcarlo.hweb 431 2005-08-16 15:41:01Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@*2 Quasi Monte Carlo quadrature. This is {\tt quasi\_mcarlo.h} file.
This defines quasi Monte Carlo quadratures for cube and for a function
multiplied by normal density. The quadrature for a cube is named
|QMCarloCubeQuadrature| and integrates:
$$\int_{\langle 0,1\rangle^n}f(x){\rm d}x$$
The quadrature for a function of normally distributed parameters is
named |QMCarloNormalQuadrature| and integrates:
$${1\over\sqrt{(2\pi)^n}}\int_{(-\infty,\infty)^n}f(x)e^{-{1\over 2}x^Tx}{\rm d}x$$
For a cube we define |qmcpit| as iterator of |QMCarloCubeQuadrature|,
and for the normal density multiplied function we define |qmcnpit| as
iterator of |QMCarloNormalQuadrature|.
The quasi Monte Carlo method generates low discrepancy points with
equal weights. The one dimensional low discrepancy sequences are
generated by |RadicalInverse| class, the sequences are combined for
higher dimensions by |HaltonSequence| class. The Halton sequence can
use a permutation scheme; |PermutattionScheme| is an abstract class
for all permutaton schemes. We have three implementations:
|WarnockPerScheme|, |ReversePerScheme|, and |IdentityPerScheme|.
@s PermutationScheme int
@s RadicalInverse int
@s HaltonSequence int
@s QMCSpecification int
@s qmcpit int
@s QMCarloCubeQuadrature int
@s qmcnpit int
@s QMCarloNormalQuadrature int
@s WarnockPerScheme int
@s ReversePerScheme int
@s IdentityPerScheme int
@c
#ifndef QUASI_MCARLO_H
#define QUASI_MCARLO_H
#include "int_sequence.h"
#include "quadrature.h"
#include "Vector.h"
#include <vector>
@<|PermutationScheme| class declaration@>;
@<|RadicalInverse| class declaration@>;
@<|HaltonSequence| class declaration@>;
@<|QMCSpecification| class declaration@>;
@<|qmcpit| class declaration@>;
@<|QMCarloCubeQuadrature| class declaration@>;
@<|qmcnpit| class declaration@>;
@<|QMCarloNormalQuadrature| class declaration@>;
@<|WarnockPerScheme| class declaration@>;
@<|ReversePerScheme| class declaration@>;
@<|IdentityPerScheme| class declaration@>;
#endif
@ This abstract class declares |permute| method which permutes
coefficient |c| having index of |i| fro the base |base| and returns
the permuted coefficient which must be in $0,\ldots,base-1$.
@<|PermutationScheme| class declaration@>=
class PermutationScheme {
public:@;
PermutationScheme()@+ {}
virtual ~PermutationScheme()@+ {}
virtual int permute(int i, int base, int c) const =0;
};
@ This class represents an integer number |num| as
$c_0+c_1b+c_2b^2+\ldots+c_jb^j$, where $b$ is |base| and
$c_0,\ldots,c_j$ is stored in |coeff|. The size of |IntSequence| coeff
does not grow with growing |num|, but is fixed from the very beginning
and is set according to supplied maximum |maxn|.
The basic method is |eval| which evaluates the |RadicalInverse| with a
given permutation scheme and returns the point, and |increase| which
increases |num| and recalculates the coefficients.
@<|RadicalInverse| class declaration@>=
class RadicalInverse {
int num;
int base;
int maxn;
int j;
IntSequence coeff;
public:@;
RadicalInverse(int n, int b, int mxn);
RadicalInverse(const RadicalInverse& ri)
: num(ri.num), base(ri.base), maxn(ri.maxn), j(ri.j), coeff(ri.coeff)@+ {}
const RadicalInverse& operator=(const RadicalInverse& radi)
{
num = radi.num; base = radi.base; maxn = radi.maxn;
j = radi.j; coeff = radi.coeff;
return *this;
}
double eval(const PermutationScheme& p) const;
void increase();
void print() const;
};
@ This is a vector of |RadicalInverse|s, each |RadicalInverse| has a
different prime as its base. The static members |primes| and
|num_primes| define a precalculated array of primes. The |increase|
method of the class increases indices in all |RadicalInverse|s and
sets point |pt| to contain the points in each dimension.
@<|HaltonSequence| class declaration@>=
class HaltonSequence {
private:@;
static int primes[];
static int num_primes;
protected:@;
int num;
int maxn;
vector<RadicalInverse> ri;
const PermutationScheme& per;
Vector pt;
public:@;
HaltonSequence(int n, int mxn, int dim, const PermutationScheme& p);
HaltonSequence(const HaltonSequence& hs)
: num(hs.num), maxn(hs.maxn), ri(hs.ri), per(hs.per), pt(hs.pt)@+ {}
const HaltonSequence& operator=(const HaltonSequence& hs);
void increase();
const Vector& point() const
{@+ return pt;@+}
const int getNum() const
{@+ return num;@+}
void print() const;
protected:@;
void eval();
};
@ This is a specification of quasi Monte Carlo quadrature. It consists
of dimension |dim|, number of points (or level) |lev|, and the
permutation scheme. This class is common to all quasi Monte Carlo
classes.
@<|QMCSpecification| class declaration@>=
class QMCSpecification {
protected:@;
int dim;
int lev;
const PermutationScheme& per_scheme;
public:@;
QMCSpecification(int d, int l, const PermutationScheme& p)
: dim(d), lev(l), per_scheme(p)@+ {}
virtual ~QMCSpecification() {}
int dimen() const
{@+ return dim;@+}
int level() const
{@+ return lev;@+}
const PermutationScheme& getPerScheme() const
{@+ return per_scheme;@+}
};
@ This is an iterator for quasi Monte Carlo over a cube
|QMCarloCubeQuadrature|. The iterator maintains |HaltonSequence| of
the same dimension as given by the specification. An iterator can be
constructed from a given number |n|, or by a copy constructor. For
technical reasons, there is also an empty constructor; for that
reason, every member is a pointer.
@<|qmcpit| class declaration@>=
class qmcpit {
protected:@;
const QMCSpecification* spec;
HaltonSequence* halton;
ParameterSignal* sig;
public:@;
qmcpit();
qmcpit(const QMCSpecification& s, int n);
qmcpit(const qmcpit& qpit);
~qmcpit();
bool operator==(const qmcpit& qpit) const;
bool operator!=(const qmcpit& qpit) const
{@+ return ! operator==(qpit);@+}
const qmcpit& operator=(const qmcpit& qpit);
qmcpit& operator++();
const ParameterSignal& signal() const
{@+ return *sig;@+}
const Vector& point() const
{@+ return halton->point();@+}
double weight() const;
void print() const
{@+ halton->print();@+}
};
@ This is an easy declaration of quasi Monte Carlo quadrature for a
cube. Everything important has been done in its iterator |qmcpit|, so
we only inherit from general |Quadrature| and reimplement |begin| and
|numEvals|.
@<|QMCarloCubeQuadrature| class declaration@>=
class QMCarloCubeQuadrature : public QuadratureImpl<qmcpit>, public QMCSpecification {
public:@;
QMCarloCubeQuadrature(int d, int l, const PermutationScheme& p)
: QuadratureImpl<qmcpit>(d), QMCSpecification(d, l, p)@+ {}
virtual ~QMCarloCubeQuadrature()@+ {}
int numEvals(int l) const
{@+ return l;@+}
protected:@;
qmcpit begin(int ti, int tn, int lev) const
{@+ return qmcpit(*this, ti*level()/tn + 1);@+}
};
@ This is an iterator for |QMCarloNormalQuadrature|. It is equivalent
to an iterator for quasi Monte Carlo cube quadrature but a point. The
point is obtained from a point of |QMCarloCubeQuadrature| by a
transformation $\langle
0,1\rangle\rightarrow\langle-\infty,\infty\rangle$ aplied to all
dimensions. The transformation yields a normal distribution from a
uniform distribution on $\langle0,1\rangle$. It is in fact
|NormalICDF|.
@<|qmcnpit| class declaration@>=
class qmcnpit : public qmcpit {
protected:@;
Vector* pnt;
public:@;
qmcnpit();
qmcnpit(const QMCSpecification& spec, int n);
qmcnpit(const qmcnpit& qpit);
~qmcnpit();
bool operator==(const qmcnpit& qpit) const
{@+ return qmcpit::operator==(qpit);@+}
bool operator!=(const qmcnpit& qpit) const
{@+ return ! operator==(qpit);@+}
const qmcnpit& operator=(const qmcnpit& qpit);
qmcnpit& operator++();
const ParameterSignal& signal() const
{@+ return *sig;@+}
const Vector& point() const
{@+ return *pnt;@+}
void print() const
{@+ halton->print();pnt->print();@+}
};
@ This is an easy declaration of quasi Monte Carlo quadrature for a
cube. Everything important has been done in its iterator |qmcnpit|, so
we only inherit from general |Quadrature| and reimplement |begin| and
|numEvals|.
@<|QMCarloNormalQuadrature| class declaration@>=
class QMCarloNormalQuadrature : public QuadratureImpl<qmcnpit>, public QMCSpecification {
public:@;
QMCarloNormalQuadrature(int d, int l, const PermutationScheme& p)
: QuadratureImpl<qmcnpit>(d), QMCSpecification(d, l, p)@+ {}
virtual ~QMCarloNormalQuadrature()@+ {}
int numEvals(int l) const
{@+ return l;@+}
protected:@;
qmcnpit begin(int ti, int tn, int lev) const
{@+ return qmcnpit(*this, ti*level()/tn + 1);@+}
};
@ Declares Warnock permutation scheme.
@<|WarnockPerScheme| class declaration@>=
class WarnockPerScheme : public PermutationScheme {
public:@;
int permute(int i, int base, int c) const;
};
@ Declares reverse permutation scheme.
@<|ReversePerScheme| class declaration@>=
class ReversePerScheme : public PermutationScheme {
public:@;
int permute(int i, int base, int c) const;
};
@ Declares no permutation (identity) scheme.
@<|IdentityPerScheme| class declaration@>=
class IdentityPerScheme : public PermutationScheme {
public:@;
int permute(int i, int base, int c) const
{@+ return c;@+}
};
@ End of {\tt quasi\_mcarlo.h} file

View File

@ -0,0 +1,220 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
#include "smolyak.hh"
#include "symmetry.hh"
#include <iostream>
#include <iomanip>
/* This constructs a beginning of isum summand in smolq. We must be careful
here, since isum can be past-the-end, so no reference to vectors in
smolq by isum must be done in this case. */
smolpit::smolpit(const SmolyakQuadrature &q, unsigned int isum)
: smolq(q), isummand(isum),
jseq(q.dimen(), 0),
sig{q.dimen()},
p{q.dimen()}
{
if (isummand < q.numSummands())
setPointAndWeight();
}
bool
smolpit::operator==(const smolpit &spit) const
{
return &smolq == &spit.smolq && isummand == spit.isummand && jseq == spit.jseq;
}
/* We first try to increase index within the current summand. If we are at
maximum, we go to a subsequent summand. Note that in this case all indices
in jseq will be zero, so no change is needed. */
smolpit &
smolpit::operator++()
{
const IntSequence &levpts = smolq.levpoints[isummand];
int i = smolq.dimen()-1;
jseq[i]++;
while (i >= 0 && jseq[i] == levpts[i])
{
jseq[i] = 0;
i--;
if (i >= 0)
jseq[i]++;
}
sig.signalAfter(std::max(i, 0));
if (i < 0)
isummand++;
if (isummand < smolq.numSummands())
setPointAndWeight();
return *this;
}
/* Here we set the point coordinates according to jseq and
isummand. Also the weight is set here. */
void
smolpit::setPointAndWeight()
{
// todo: raise if isummand ≥ smolq.numSummands()
int l = smolq.level;
int d = smolq.dimen();
int sumk = (smolq.levels[isummand]).sum();
int m1exp = l + d - sumk - 1;
w = (2*(m1exp/2) == m1exp) ? 1.0 : -1.0;
w *= PascalTriangle::noverk(d-1, sumk-l);
for (int i = 0; i < d; i++)
{
int ki = (smolq.levels[isummand])[i];
p[i] = (smolq.uquad).point(ki, jseq[i]);
w *= (smolq.uquad).weight(ki, jseq[i]);
}
}
/* Debug print. */
void
smolpit::print() const
{
auto ff = std::cout.flags();
std::cout << "isum=" << std::left << std::setw(3) << isummand << std::right << ": [";
for (int i = 0; i < smolq.dimen(); i++)
std::cout << std::setw(2) << (smolq.levels[isummand])[i] << ' ';
std::cout << "] j=[";
for (int i = 0; i < smolq.dimen(); i++)
std::cout << std::setw(2) << jseq[i] << ' ';
std::cout << std::showpos << std::fixed << std::setprecision(3)
<< "] " << std::setw(4) << w << "*(";
for (int i = 0; i < smolq.dimen()-1; i++)
std::cout << std::setw(4) << p[i] << ' ';
std::cout << std::setw(4) << p[smolq.dimen()-1] << ')' << std::endl;
std::cout.flags(ff);
}
/* Here is the constructor of SmolyakQuadrature. We have to setup levels,
levpoints and cumevals. We have to go through all d-dimensional
sequences k, such that l|k|l+d1 and all k are positive integers. This is
equivalent to going through all k such that ld|k|l1 and all k are
non-negative integers. This is equivalent to going through d+1 dimensional
sequences (k,x) such that |(k,x)|=l1 and x=0,,d1. The resulting sequence
of positive integers is obtained by adding 1 to all k. */
SmolyakQuadrature::SmolyakQuadrature(int d, int l, const OneDQuadrature &uq)
: QuadratureImpl<smolpit>(d), level(l), uquad(uq)
{
// TODO: check l>1, l≥d
// TODO: check l≥uquad.miLevel(), l≤uquad.maxLevel()
int cum = 0;
for (const auto &si : SymmetrySet(l-1, d+1))
{
if (si[d] <= d-1)
{
IntSequence lev(si, 0, d);
lev.add(1);
levels.push_back(lev);
IntSequence levpts(d);
for (int i = 0; i < d; i++)
levpts[i] = uquad.numPoints(lev[i]);
levpoints.push_back(levpts);
cum += levpts.mult();
cumevals.push_back(cum);
}
}
}
/* Here we return a number of evalutions of the quadrature for the given level.
If the given level is the current one, we simply return the maximum
cumulative number of evaluations. Otherwise we call costly
calcNumEvaluations() method. */
int
SmolyakQuadrature::numEvals(int l) const
{
if (l != level)
return calcNumEvaluations(l);
else
return cumevals[numSummands()-1];
}
/* This divides all the evaluations to tn approximately equal groups, and
returns the beginning of the specified group ti. The granularity of
divisions are summands as listed by levels. */
smolpit
SmolyakQuadrature::begin(int ti, int tn, int l) const
{
// TODO: raise is level≠l
if (ti == tn)
return smolpit(*this, numSummands());
int totevals = cumevals[numSummands()-1];
int evals = (totevals*ti)/tn;
unsigned int isum = 0;
while (isum+1 < numSummands() && cumevals[isum+1] < evals)
isum++;
return smolpit(*this, isum);
}
/* This is the same in a structure as SmolyakQuadrature constructor. We have to
go through all summands and calculate a number of evaluations in each
summand. */
int
SmolyakQuadrature::calcNumEvaluations(int lev) const
{
int cum = 0;
for (const auto &si : SymmetrySet(lev-1, dim+1))
{
if (si[dim] <= dim-1)
{
IntSequence lev(si, 0, dim);
lev.add(1);
IntSequence levpts(dim);
for (int i = 0; i < dim; i++)
levpts[i] = uquad.numPoints(lev[i]);
cum += levpts.mult();
}
}
return cum;
}
/* This returns a maximum level such that the number of evaluations is less
than the given number. */
void
SmolyakQuadrature::designLevelForEvals(int max_evals, int &lev, int &evals) const
{
int last_evals;
evals = 1;
lev = 1;
do
{
lev++;
last_evals = evals;
evals = calcNumEvaluations(lev);
}
while (lev < uquad.numLevels() && evals <= max_evals);
lev--;
evals = last_evals;
}

View File

@ -1,294 +0,0 @@
@q $Id: smolyak.cweb 1208 2007-03-19 21:33:12Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@ This is {\tt smolyak.cpp} file.
@c
#include "smolyak.h"
#include "symmetry.h"
@<|smolpit| empty constructor@>;
@<|smolpit| regular constructor@>;
@<|smolpit| copy constructor@>;
@<|smolpit| destructor@>;
@<|smolpit::operator==| code@>;
@<|smolpit::operator=| code@>;
@<|smolpit::operator++| code@>;
@<|smolpit::setPointAndWeight| code@>;
@<|smolpit::print| code@>;
@<|SmolyakQuadrature| constructor@>;
@<|SmolyakQuadrature::numEvals| code@>;
@<|SmolyakQuadrature::begin| code@>;
@<|SmolyakQuadrature::calcNumEvaluations| code@>;
@<|SmolyakQuadrature::designLevelForEvals| code@>;
@
@<|smolpit| empty constructor@>=
smolpit::smolpit()
: smolq(NULL), isummand(0), jseq(NULL), sig(NULL), p(NULL)
{
}
@ This constructs a beginning of |isum| summand in |smolq|. We must be
careful here, since |isum| can be past-the-end, so no reference to
vectors in |smolq| by |isum| must be done in this case.
@<|smolpit| regular constructor@>=
smolpit::smolpit(const SmolyakQuadrature& q, unsigned int isum)
: smolq(&q), isummand(isum), jseq(new IntSequence(q.dimen(), 0)),
sig(new ParameterSignal(q.dimen())), p(new Vector(q.dimen()))
{
if (isummand < q.numSummands()) {
setPointAndWeight();
}
}
@
@<|smolpit| copy constructor@>=
smolpit::smolpit(const smolpit& spit)
: smolq(spit.smolq), isummand(spit.isummand), w(spit.w)
{
if (spit.jseq)
jseq = new IntSequence(*(spit.jseq));
else
jseq = NULL;
if (spit.sig)
sig = new ParameterSignal(*(spit.sig));
else
sig = NULL;
if (spit.p)
p = new Vector(*(spit.p));
else
p = NULL;
}
@
@<|smolpit| destructor@>=
smolpit::~smolpit()
{
if (jseq)
delete jseq;
if (sig)
delete sig;
if (p)
delete p;
}
@
@<|smolpit::operator==| code@>=
bool smolpit::operator==(const smolpit& spit) const
{
bool ret = true;
ret = ret & smolq == spit.smolq;
ret = ret & isummand == spit.isummand;
ret = ret & ((jseq==NULL && spit.jseq==NULL) ||
(jseq!=NULL && spit.jseq!=NULL && *jseq == *(spit.jseq)));
return ret;
}
@
@<|smolpit::operator=| code@>=
const smolpit& smolpit::operator=(const smolpit& spit)
{
smolq = spit.smolq;
isummand = spit.isummand;
w = spit.w;
if (jseq)
delete jseq;
if (sig)
delete sig;
if (p)
delete p;
if (spit.jseq)
jseq = new IntSequence(*(spit.jseq));
else
jseq = NULL;
if (spit.sig)
sig = new ParameterSignal(*(spit.sig));
else
sig = NULL;
if (spit.p)
p = new Vector(*(spit.p));
else
p = NULL;
return *this;
}
@ We first try to increase index within the current summand. If we are
at maximum, we go to a subsequent summand. Note that in this case all
indices in |jseq| will be zero, so no change is needed.
@<|smolpit::operator++| code@>=
smolpit& smolpit::operator++()
{
// todo: throw if |smolq==NULL| or |jseq==NULL| or |sig==NULL|
const IntSequence& levpts = smolq->levpoints[isummand];
int i = smolq->dimen()-1;
(*jseq)[i]++;
while (i >= 0 && (*jseq)[i] == levpts[i]) {
(*jseq)[i] = 0;
i--;
if (i >= 0)
(*jseq)[i]++;
}
sig->signalAfter(std::max(i,0));
if (i < 0)
isummand++;
if (isummand < smolq->numSummands())
setPointAndWeight();
return *this;
}
@ Here we set the point coordinates according to |jseq| and
|isummand|. Also the weight is set here.
@<|smolpit::setPointAndWeight| code@>=
void smolpit::setPointAndWeight()
{
// todo: raise if |smolq==NULL| or |jseq==NULL| or |sig==NULL| or
// |p==NULL| or |isummand>=smolq->numSummands()|
int l = smolq->level;
int d = smolq->dimen();
int sumk = (smolq->levels[isummand]).sum();
int m1exp = l + d - sumk - 1;
w = (2*(m1exp/2)==m1exp)? 1.0 : -1.0;
w *= smolq->psc.noverk(d-1, sumk-l);
for (int i = 0; i < d; i++) {
int ki = (smolq->levels[isummand])[i];
(*p)[i] = (smolq->uquad).point(ki, (*jseq)[i]);
w *= (smolq->uquad).weight(ki, (*jseq)[i]);
}
}
@ Debug print.
@<|smolpit::print| code@>=
void smolpit::print() const
{
printf("isum=%-3d: [", isummand);
for (int i = 0; i < smolq->dimen(); i++)
printf("%2d ", (smolq->levels[isummand])[i]);
printf("] j=[");
for (int i = 0; i < smolq->dimen(); i++)
printf("%2d ", (*jseq)[i]);
printf("] %+4.3f*(",w);
for (int i = 0; i < smolq->dimen()-1; i++)
printf("%+4.3f ", (*p)[i]);
printf("%+4.3f)\n",(*p)[smolq->dimen()-1]);
}
@ Here is the constructor of |SmolyakQuadrature|. We have to setup
|levels|, |levpoints| and |cumevals|. We have to go through all
$d$-dimensional sequences $k$, such that $l\leq \vert k\vert\leq
l+d-1$ and all $k_i$ are positive integers. This is equivalent to
going through all $k$ such that $l-d\leq\vert k\vert\leq l-1$ and all
$k_i$ are non-negative integers. This is equivalent to going through
$d+1$ dimensional sequences $(k,x)$ such that $\vert(k,x)\vert =l-1$
and $x=0,\ldots,d-1$. The resulting sequence of positive integers is
obtained by adding $1$ to all $k_i$.
@<|SmolyakQuadrature| constructor@>=
SmolyakQuadrature::SmolyakQuadrature(int d, int l, const OneDQuadrature& uq)
: QuadratureImpl<smolpit>(d), level(l), uquad(uq), psc(d-1,d-1)
{
// todo: check |l>1|, |l>=d|
// todo: check |l>=uquad.miLevel()|, |l<=uquad.maxLevel()|
int cum = 0;
SymmetrySet ss(l-1, d+1);
for (symiterator si(ss); !si.isEnd(); ++si) {
if ((*si)[d] <= d-1) {
IntSequence lev((const IntSequence&)*si, 0, d);
lev.add(1);
levels.push_back(lev);
IntSequence levpts(d);
for (int i = 0; i < d; i++)
levpts[i] = uquad.numPoints(lev[i]);
levpoints.push_back(levpts);
cum += levpts.mult();
cumevals.push_back(cum);
}
}
}
@ Here we return a number of evalutions of the quadrature for the
given level. If the given level is the current one, we simply return
the maximum cumulative number of evaluations. Otherwise we call costly
|calcNumEvaluations| method.
@<|SmolyakQuadrature::numEvals| code@>=
int SmolyakQuadrature::numEvals(int l) const
{
if (l != level)
return calcNumEvaluations(l);
else
return cumevals[numSummands()-1];
}
@ This divides all the evaluations to |tn| approximately equal groups,
and returns the beginning of the specified group |ti|. The granularity
of divisions are summands as listed by |levels|.
@<|SmolyakQuadrature::begin| code@>=
smolpit SmolyakQuadrature::begin(int ti, int tn, int l) const
{
// todo: raise is |level!=l|
if (ti == tn)
return smolpit(*this, numSummands());
int totevals = cumevals[numSummands()-1];
int evals = (totevals*ti)/tn;
unsigned int isum = 0;
while (isum+1 < numSummands() && cumevals[isum+1] < evals)
isum++;
return smolpit(*this, isum);
}
@ This is the same in a structure as |@<|SmolyakQuadrature| constructor@>|.
We have to go through all summands and calculate
a number of evaluations in each summand.
@<|SmolyakQuadrature::calcNumEvaluations| code@>=
int SmolyakQuadrature::calcNumEvaluations(int lev) const
{
int cum = 0;
SymmetrySet ss(lev-1, dim+1);
for (symiterator si(ss); !si.isEnd(); ++si) {
if ((*si)[dim] <= dim-1) {
IntSequence lev((const IntSequence&)*si, 0, dim);
lev.add(1);
IntSequence levpts(dim);
for (int i = 0; i < dim; i++)
levpts[i] = uquad.numPoints(lev[i]);
cum += levpts.mult();
}
}
return cum;
}
@ This returns a maximum level such that the number of evaluations is
less than the given number.
@<|SmolyakQuadrature::designLevelForEvals| code@>=
void SmolyakQuadrature::designLevelForEvals(int max_evals, int& lev, int& evals) const
{
int last_evals;
evals = 1;
lev = 1;
do {
lev++;
last_evals = evals;
evals = calcNumEvaluations(lev);
} while (lev < uquad.numLevels() && evals <= max_evals);
lev--;
evals = last_evals;
}
@ End of {\tt smolyak.cpp} file

View File

@ -0,0 +1,149 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
// Smolyak quadrature.
/* This file defines Smolyak (sparse grid) multidimensional quadrature for
non-nested underlying one dimensional quadrature. Let Q¹ denote the one
dimensional quadrature of l level. Let n denote a number of points in the l
level. Than the Smolyak quadrature can be defined as
d1
Qf = (1)^{l+d|k|1} (Q¹_kQ¹_{k_d})f
l|k|l+d1 |k|l
where d is the dimension, k is d-dimensional sequence of integers, and |k|
denotes the sum of the sequence.
Here we define smolpit as Smolyak iterator and SmolyakQuadrature. */
#ifndef SMOLYAK_H
#define SMOLYAK_H
#include "int_sequence.hh"
#include "tl_static.hh"
#include "vector_function.hh"
#include "quadrature.hh"
#include "pascal_triangle.hh"
/* Here we define the Smolyak point iterator. The Smolyak formula can be broken
to a sum of product quadratures with various combinations of levels. The
iterator follows this pattern. It maintains an index to a summand and then a
point coordinates within the summand (product quadrature). The array of
summands to which the isummand points is maintained by the
SmolyakQuadrature class to which the object knows the pointer smolq.
We provide a constructor which points to the beginning of the given summand.
This constructor is used in SmolyakQuadrature::begin() method which
approximately divideds all the iterators to subsets of equal size. */
class SmolyakQuadrature;
class smolpit
{
protected:
const SmolyakQuadrature &smolq;
unsigned int isummand{0};
IntSequence jseq;
ParameterSignal sig;
Vector p;
double w;
public:
smolpit(const SmolyakQuadrature &q, unsigned int isum);
smolpit(const smolpit &spit) = default;
~smolpit() = default;
bool operator==(const smolpit &spit) const;
bool
operator!=(const smolpit &spit) const
{
return !operator==(spit);
}
smolpit &operator=(const smolpit &spit) = delete;
smolpit &operator++();
const ParameterSignal &
signal() const
{
return sig;
}
const Vector &
point() const
{
return p;
}
double
weight() const
{
return w;
}
void print() const;
protected:
void setPointAndWeight();
};
/* Here we define the class SmolyakQuadrature. It maintains an array of
summands of the Smolyak quadrature formula:
d1
(1)^{l+d|k|1} (Q¹_kQ¹_{k_d})f
l|k|l+d1 |k|l
Each summand is fully specified by sequence k. The summands are here
represented (besides k) also by sequence of number of points in each level
selected by k, and also by a cummulative number of evaluations. The latter
two are added only for conveniency.
The summands in the code are given by levels, which is a vector of
k sequences, further by levpoints which is a vector of sequences
of nuber of points in each level, and by cumevals which is the
cumulative number of points, this is:
d
n_k
¹
where the sum is done through all k before the current.
The levels and levpoints vectors are used by smolpit. */
class SmolyakQuadrature : public QuadratureImpl<smolpit>
{
friend class smolpit;
int level;
const OneDQuadrature &uquad;
std::vector<IntSequence> levels;
std::vector<IntSequence> levpoints;
std::vector<int> cumevals;
public:
SmolyakQuadrature(int d, int l, const OneDQuadrature &uq);
~SmolyakQuadrature() override = default;
int numEvals(int level) const override;
void designLevelForEvals(int max_eval, int &lev, int &evals) const;
protected:
smolpit begin(int ti, int tn, int level) const override;
unsigned int
numSummands() const
{
return levels.size();
}
private:
int calcNumEvaluations(int level) const;
};
#endif

View File

@ -1,123 +0,0 @@
@q $Id: smolyak.hweb 431 2005-08-16 15:41:01Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@*2 Smolyak quadrature. This is {\tt smolyak.h} file
This file defines Smolyak (sparse grid) multidimensional quadrature
for non-nested underlying one dimensional quadrature. Let $Q^1_l$ denote
the one dimensional quadrature of $l$ level. Let $n_l$ denote a
number of points in the $l$ level. Than the Smolyak quadrature can be
defined as
$$Q^df=\sum_{l\leq\vert k\vert\leq l+d-1}(-1)^{l+d-\vert k\vert-1}\left(\matrix{d-1\cr
\vert k\vert-l}\right)(Q_{k_1}^1\otimes\ldots\otimes Q_{k_d}^1)f,$$
where $d$ is the dimension, $k$ is $d$-dimensional sequence of
integers, and $\vert k\vert$ denotes a sum of the sequence.
Here we define |smolpit| as Smolyak iterator and |SmolyakQuadrature|.
@s smolpit int
@s SmolyakQuadrature int
@s PascalTriangle int
@s SymmetrySet int
@s symiterator int
@c
#ifndef SMOLYAK_H
#define SMOLYAK_H
#include "int_sequence.h"
#include "tl_static.h"
#include "vector_function.h"
#include "quadrature.h"
@<|smolpit| class declaration@>;
@<|SmolyakQuadrature| class declaration@>;
#endif
@ Here we define the Smolyak point iterator. The Smolyak formula can
be broken to a sum of product quadratures with various combinations of
levels. The iterator follows this pattern. It maintains an index to a
summand and then a point coordinates within the summand (product
quadrature). The array of summands to which the |isummand| points is
maintained by the |SmolyakQuadrature| class to which the object knows
the pointer |smolq|.
We provide a constructor which points to the beginning of the given
summand. This constructor is used in |SmolyakQuadrature::begin| method
which approximately divideds all the iterators to subsets of equal
size.
@<|smolpit| class declaration@>=
class SmolyakQuadrature;
class smolpit {
protected:@;
const SmolyakQuadrature* smolq;
unsigned int isummand;
IntSequence* jseq;
ParameterSignal* sig;
Vector* p;
double w;
public:@;
smolpit();
smolpit(const SmolyakQuadrature& q, unsigned int isum);
smolpit(const smolpit& spit);
~smolpit();
bool operator==(const smolpit& spit) const;
bool operator!=(const smolpit& spit) const
{@+ return ! operator==(spit);@+}
const smolpit& operator=(const smolpit& spit);
smolpit& operator++();
const ParameterSignal& signal() const
{@+ return *sig;@+}
const Vector& point() const
{@+ return *p;@+}
double weight() const
{@+ return w;@+}
void print() const;
protected:@;
void setPointAndWeight();
};
@ Here we define the class |SmolyakQuadrature|. It maintains an array
of summands of the Smolyak quadrature formula:
$$\sum_{l\leq\vert k\vert\leq l+d-1}(-1)^{l+d-\vert
k\vert-1}\left(\matrix{d-1\cr
\vert k\vert-l}\right)(Q_{k_1}^1\otimes\ldots\otimes Q_{k_d}^1)f$$
Each summand is fully specified by sequence $k$. The summands are here
represented (besides $k$) also by sequence of number of points in each
level selected by $k$, and also by a cummulative number of
evaluations. The latter two are added only for conveniency.
The summands in the code are given by |levels|, which is a vector of
$k$ sequences, further by |levpoints| which is a vector of sequences
of nuber of points in each level, and by |cumevals| which is the
cumulative number of points, this is $\sum_k\prod_{i=1}^dn_{k_i}$,
where the sum is done through all $k$ before the current.
The |levels| and |levpoints| vectors are used by |smolpit|.
@<|SmolyakQuadrature| class declaration@>=
class SmolyakQuadrature : public QuadratureImpl<smolpit> {
friend class smolpit;
int level;
const OneDQuadrature& uquad;
vector<IntSequence> levels;
vector<IntSequence> levpoints;
vector<int> cumevals;
PascalTriangle psc;
public:@;
SmolyakQuadrature(int d, int l, const OneDQuadrature& uq);
virtual ~SmolyakQuadrature()@+ {}
virtual int numEvals(int level) const;
void designLevelForEvals(int max_eval, int& lev, int& evals) const;
protected:@;
smolpit begin(int ti, int tn, int level) const;
unsigned int numSummands() const
{@+ return levels.size();@+}
private:@;
int calcNumEvaluations(int level) const;
};
@ End of {\tt smolyak.h} file

View File

@ -0,0 +1,148 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
#include "vector_function.hh"
#include <dynlapack.h>
#include <cmath>
#include <algorithm>
/* Just an easy constructor of sequence of booleans defaulting to change
everywhere. */
ParameterSignal::ParameterSignal(int n)
: data(n, true)
{
}
/* This sets false (no change) before a given parameter, and true (change)
after the given parameter (including). */
void
ParameterSignal::signalAfter(int l)
{
for (size_t i = 0; i < std::min(static_cast<size_t>(l), data.size()); i++)
data[i] = false;
for (size_t i = l; i < data.size(); i++)
data[i] = true;
}
/* This constructs a function set hardcopying also the first. */
VectorFunctionSet::VectorFunctionSet(const VectorFunction &f, int n)
: funcs(n)
{
for (int i = 0; i < n; i++)
{
func_copies.push_back(f.clone());
funcs[i] = func_copies.back().get();
}
}
/* This constructs a function set with shallow copy in the first and hard
copies in others. */
VectorFunctionSet::VectorFunctionSet(VectorFunction &f, int n)
: funcs(n)
{
if (n > 0)
funcs[0] = &f;
for (int i = 1; i < n; i++)
{
func_copies.push_back(f.clone());
funcs[i] = func_copies.back().get();
}
}
/* Here we construct the object from the given function f and given
variance-covariance matrix Σ=vcov. The matrix A is calculated as lower
triangular and yields Σ=AA. */
GaussConverterFunction::GaussConverterFunction(VectorFunction &f, const GeneralMatrix &vcov)
: VectorFunction(f), func(&f), A(vcov.nrows(), vcov.nrows()),
multiplier(calcMultiplier())
{
// TODO: raise if A.nrows() ≠ indim()
calcCholeskyFactor(vcov);
}
GaussConverterFunction::GaussConverterFunction(std::unique_ptr<VectorFunction> f, const GeneralMatrix &vcov)
: VectorFunction(*f), func_storage{move(f)}, func{func_storage.get()}, A(vcov.nrows(), vcov.nrows()),
multiplier(calcMultiplier())
{
// TODO: raise if A.nrows() ≠ indim()
calcCholeskyFactor(vcov);
}
GaussConverterFunction::GaussConverterFunction(const GaussConverterFunction &f)
: VectorFunction(f), func_storage{f.func->clone()}, func{func_storage.get()}, A(f.A),
multiplier(f.multiplier)
{
}
/* Here we evaluate the function
g(y) = 1/(π) f(2·Ay).
Since the matrix A is lower triangular, the change signal for the function f
will look like (0,,0,1,,1) where the first 1 is in the same position as
the first change in the given signal sig of the input y=point. */
void
GaussConverterFunction::eval(const Vector &point, const ParameterSignal &sig, Vector &out)
{
ParameterSignal s(sig);
int i = 0;
while (i < indim() && !sig[i])
i++;
s.signalAfter(i);
Vector x(indim());
x.zeros();
A.multaVec(x, point);
x.mult(sqrt(2.0));
func->eval(x, s, out);
out.mult(multiplier);
}
/* This returns 1/√(πⁿ). */
double
GaussConverterFunction::calcMultiplier() const
{
return sqrt(pow(M_PI, -1*indim()));
}
void
GaussConverterFunction::calcCholeskyFactor(const GeneralMatrix &vcov)
{
A = vcov;
lapack_int rows = A.nrows(), lda = A.getLD();
for (int i = 0; i < rows; i++)
for (int j = i+1; j < rows; j++)
A.get(i, j) = 0.0;
lapack_int info;
dpotrf("L", &rows, A.base(), &lda, &info);
// TODO: raise if info≠1
}

View File

@ -1,190 +0,0 @@
@q $Id: vector_function.cweb 431 2005-08-16 15:41:01Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@ This is {\tt vector\_function.cpp} file
@c
#include "vector_function.h"
#include <dynlapack.h>
#include <cmath>
#include <cstring>
#include <algorithm>
#ifdef __MINGW32__
#define __CROSS_COMPILATION__
#endif
#ifdef __MINGW64__
#define __CROSS_COMPILATION__
#endif
#ifdef __CROSS_COMPILATION__
#define M_PI 3.14159265358979323846
#endif
@<|ParameterSignal| constructor code@>;
@<|ParameterSignal| copy constructor code@>;
@<|ParameterSignal::signalAfter| code@>;
@<|VectorFunctionSet| constructor 1 code@>;
@<|VectorFunctionSet| constructor 2 code@>;
@<|VectorFunctionSet| destructor code@>;
@<|GaussConverterFunction| constructor code 1@>;
@<|GaussConverterFunction| constructor code 2@>;
@<|GaussConverterFunction| copy constructor code@>;
@<|GaussConverterFunction::eval| code@>;
@<|GaussConverterFunction::multiplier| code@>;
@<|GaussConverterFunction::calcCholeskyFactor| code@>;
@ Just an easy constructor of sequence of booleans defaulting to
change everywhere.
@<|ParameterSignal| constructor code@>=
ParameterSignal::ParameterSignal(int n)
: data(new bool[n]), num(n)
{
for (int i = 0; i < num; i++)
data[i] = true;
}
@
@<|ParameterSignal| copy constructor code@>=
ParameterSignal::ParameterSignal(const ParameterSignal& sig)
: data(new bool[sig.num]), num(sig.num)
{
memcpy(data, sig.data, num);
}
@ This sets |false| (no change) before a given parameter, and |true|
(change) after the given parameter (including).
@<|ParameterSignal::signalAfter| code@>=
void ParameterSignal::signalAfter(int l)
{
for (int i = 0; i < std::min(l,num); i++)
data[i] = false;
for (int i = l; i < num; i++)
data[i] = true;
}
@ This constructs a function set hardcopying also the first.
@<|VectorFunctionSet| constructor 1 code@>=
VectorFunctionSet::VectorFunctionSet(const VectorFunction& f, int n)
: funcs(n), first_shallow(false)
{
for (int i = 0; i < n; i++)
funcs[i] = f.clone();
}
@ This constructs a function set with shallow copy in the first and
hard copies in others.
@<|VectorFunctionSet| constructor 2 code@>=
VectorFunctionSet::VectorFunctionSet(VectorFunction& f, int n)
: funcs(n), first_shallow(true)
{
if (n > 0)
funcs[0] = &f;
for (int i = 1; i < n; i++)
funcs[i] = f.clone();
}
@ This deletes the functions. The first is deleted only if it was not
a shallow copy.
@<|VectorFunctionSet| destructor code@>=
VectorFunctionSet::~VectorFunctionSet()
{
unsigned int start = first_shallow ? 1 : 0;
for (unsigned int i = start; i < funcs.size(); i++)
delete funcs[i];
}
@ Here we construct the object from the given function $f$ and given
variance-covariance matrix $\Sigma=$|vcov|. The matrix $A$ is
calculated as lower triangular and yields $\Sigma=AA^T$.
@<|GaussConverterFunction| constructor code 1@>=
GaussConverterFunction::GaussConverterFunction(VectorFunction& f, const GeneralMatrix& vcov)
: VectorFunction(f), func(&f), delete_flag(false), A(vcov.numRows(), vcov.numRows()),
multiplier(calcMultiplier())
{
// todo: raise if |A.numRows() != indim()|
calcCholeskyFactor(vcov);
}
@ Here we construct the object in the same way, however we mark the
function as to be deleted.
@<|GaussConverterFunction| constructor code 2@>=
GaussConverterFunction::GaussConverterFunction(VectorFunction* f, const GeneralMatrix& vcov)
: VectorFunction(*f), func(f), delete_flag(true), A(vcov.numRows(), vcov.numRows()),
multiplier(calcMultiplier())
{
// todo: raise if |A.numRows() != indim()|
calcCholeskyFactor(vcov);
}
@
@<|GaussConverterFunction| copy constructor code@>=
GaussConverterFunction::GaussConverterFunction(const GaussConverterFunction& f)
: VectorFunction(f), func(f.func->clone()), delete_flag(true), A(f.A),
multiplier(f.multiplier)
{
}
@ Here we evaluate the function
$g(y)={1\over\sqrt{\pi^n}}f\left(\sqrt{2}Ay\right)$. Since the matrix $A$ is lower
triangular, the change signal for the function $f$ will look like
$(0,\ldots,0,1,\ldots,1)$ where the first $1$ is in the same position
as the first change in the given signal |sig| of the input
$y=$|point|.
@<|GaussConverterFunction::eval| code@>=
void GaussConverterFunction::eval(const Vector& point, const ParameterSignal& sig, Vector& out)
{
ParameterSignal s(sig);
int i = 0;
while (i < indim() && !sig[i])
i++;
s.signalAfter(i);
Vector x(indim());
x.zeros();
A.multaVec(x, point);
x.mult(sqrt(2.0));
func->eval(x, s, out);
out.mult(multiplier);
}
@ This returns $1\over\sqrt{\pi^n}$.
@<|GaussConverterFunction::multiplier| code@>=
double GaussConverterFunction::calcMultiplier() const
{
return sqrt(pow(M_PI, -1*indim()));
}
@
@<|GaussConverterFunction::calcCholeskyFactor| code@>=
void GaussConverterFunction::calcCholeskyFactor(const GeneralMatrix& vcov)
{
A = vcov;
lapack_int rows = A.numRows();
for (int i = 0; i < rows; i++)
for (int j = i+1; j < rows; j++)
A.get(i,j) = 0.0;
lapack_int info;
dpotrf("L", &rows, A.base(), &rows, &info);
// todo: raise if |info!=1|
}
@ End of {\tt vector\_function.cpp} file

View File

@ -0,0 +1,186 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
// Vector function.
/* This file defines interface for functions taking a vector as an input and
returning a vector (with a different size) as an output. We are also
introducing a parameter signalling; it is a boolean vector which tracks
parameters which were changed from the previous call. The VectorFunction
implementation can exploit this information and evaluate the function more
efficiently. The information can be completely ignored.
From the signalling reason, and from other reasons, the function evaluation
is not const. */
#ifndef VECTOR_FUNCTION_H
#define VECTOR_FUNCTION_H
#include "Vector.hh"
#include "GeneralMatrix.hh"
#include <vector>
#include <memory>
/* This is a simple class representing a vector of booleans. The items night be
retrieved or changed, or can be set true after some point. This is useful
when we multiply the vector with lower triangular matrix.
true means that a parameter was changed. */
class ParameterSignal
{
protected:
std::vector<bool> data;
public:
ParameterSignal(int n);
ParameterSignal(const ParameterSignal &sig) = default;
~ParameterSignal() = default;
void signalAfter(int l);
bool
operator[](int i) const
{
return data[i];
}
std::vector<bool>::reference
operator[](int i)
{
return data[i];
}
};
/* This is the abstract class for vector function. At this level of abstraction
we only need to know size of input vector and a size of output vector.
The important thing here is a clone method, we will need to make hard copies
of vector functions since the evaluations are not const. The hardcopies
apply for parallelization. */
class VectorFunction
{
protected:
int in_dim;
int out_dim;
public:
VectorFunction(int idim, int odim)
: in_dim(idim), out_dim(odim)
{
}
VectorFunction(const VectorFunction &func) = default;
virtual ~VectorFunction() = default;
virtual std::unique_ptr<VectorFunction> clone() const = 0;
virtual void eval(const Vector &point, const ParameterSignal &sig, Vector &out) = 0;
int
indim() const
{
return in_dim;
}
int
outdim() const
{
return out_dim;
}
};
/* This makes n copies of VectorFunction. The first constructor make exactly
n new copies, the second constructor copies only the pointer to the first
and others are hard (real) copies.
The class is useful for making a given number of copies at once, and this
set can be reused many times if we need mupliple copis of the function (for
example for paralelizing the code). */
class VectorFunctionSet
{
private:
// Stores the hard copies made by the class
std::vector<std::unique_ptr<VectorFunction>> func_copies;
protected:
std::vector<VectorFunction *> funcs;
public:
VectorFunctionSet(const VectorFunction &f, int n);
VectorFunctionSet(VectorFunction &f, int n);
~VectorFunctionSet() = default;
VectorFunction &
getFunc(int i)
{
return *(funcs[i]);
}
int
getNum() const
{
return funcs.size();
}
};
/* This class wraps another VectorFunction to allow integration of a function
through normally distributed inputs. Namely, if one wants to integrate
1
f(x)e^{½x|Σ|¹x}dx
{(2π)|Σ|}
then if we write Σ=AA and x=2·Ay, we get integral
1 1
f(2·Ay)e^{½yy} (2)|A|dy = f(2·Ay)e^{½yy}dy
{(2π)|Σ|} (π)
which means that a given function f we have to wrap to yield a function
g(y) = 1/(π) f(2·Ay).
This is exactly what this class is doing. This transformation is useful
since the Gauss-Hermite points and weights are defined for weighting
function e^{y²}, so this transformation allows using Gauss-Hermite
quadratures seemlessly in a context of integration through normally
distributed inputs.
The class maintains a pointer to the function f. When the object is
constructed by the first constructor, the f is assumed to be owned by the
caller. If the object of this class is copied, then f is copied and hence
stored in a std::unique_ptr. The second constructor takes a smart pointer to
the function and in that case the class takes ownership of f. */
class GaussConverterFunction : public VectorFunction
{
private:
std::unique_ptr<VectorFunction> func_storage;
protected:
VectorFunction *func;
GeneralMatrix A;
double multiplier;
public:
GaussConverterFunction(VectorFunction &f, const GeneralMatrix &vcov);
GaussConverterFunction(std::unique_ptr<VectorFunction> f, const GeneralMatrix &vcov);
GaussConverterFunction(const GaussConverterFunction &f);
~GaussConverterFunction() override = default;
std::unique_ptr<VectorFunction>
clone() const override
{
return std::make_unique<GaussConverterFunction>(*this);
}
void eval(const Vector &point, const ParameterSignal &sig, Vector &out) override;
private:
double calcMultiplier() const;
void calcCholeskyFactor(const GeneralMatrix &vcov);
};
#endif

View File

@ -1,156 +0,0 @@
@q $Id: vector_function.hweb 431 2005-08-16 15:41:01Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@*2 Vector function. This is {\tt vector\_function.h} file
This file defines interface for functions taking a vector as an input
and returning a vector (with a different size) as an output. We are
also introducing a parameter signalling; it is a boolean vector which
tracks parameters which were changed from the previous call. The
|VectorFunction| implementation can exploit this information and
evaluate the function more efficiently. The information can be
completely ignored.
From the signalling reason, and from other reasons, the function
evaluation is not |const|.
@s ParameterSignal int
@s VectorFunction int
@s VectorFunctionSet int
@s GaussConverterFunction int
@c
#ifndef VECTOR_FUNCTION_H
#define VECTOR_FUNCTION_H
#include "Vector.h"
#include "GeneralMatrix.h"
#include <vector>
@<|ParameterSignal| class declaration@>;
@<|VectorFunction| class declaration@>;
@<|VectorFunctionSet| class declaration@>;
@<|GaussConverterFunction| class declaration@>;
#endif
@ This is a simple class representing a vector of booleans. The items
night be retrieved or changed, or can be set |true| after some
point. This is useful when we multiply the vector with lower
triangular matrix.
|true| means that a parameter was changed.
@<|ParameterSignal| class declaration@>=
class ParameterSignal {
protected:@;
bool* data;
int num;
public:@;
ParameterSignal(int n);
ParameterSignal(const ParameterSignal& sig);
~ParameterSignal()
{@+ delete [] data;@+}
void signalAfter(int l);
const bool& operator[](int i) const
{@+ return data[i];@+}
bool& operator[](int i)
{@+ return data[i];@+}
};
@ This is the abstract class for vector function. At this level of
abstraction we only need to know size of input vector and a size of
output vector.
The important thing here is a clone method, we will need to make hard
copies of vector functions since the evaluations are not |const|. The
hardcopies apply for parallelization.
@<|VectorFunction| class declaration@>=
class VectorFunction {
protected:@;
int in_dim;
int out_dim;
public:@;
VectorFunction(int idim, int odim)
: in_dim(idim), out_dim(odim)@+ {}
VectorFunction(const VectorFunction& func)
: in_dim(func.in_dim), out_dim(func.out_dim)@+ {}
virtual ~VectorFunction()@+ {}
virtual VectorFunction* clone() const =0;
virtual void eval(const Vector& point, const ParameterSignal& sig, Vector& out) =0;
int indim() const
{@+ return in_dim;@+}
int outdim() const
{@+ return out_dim;@+}
};
@ This makes |n| copies of |VectorFunction|. The first constructor
make exactly |n| new copies, the second constructor copies only the
pointer to the first and others are hard (real) copies.
The class is useful for making a given number of copies at once, and
this set can be reused many times if we need mupliple copis of the
function (for example for paralelizing the code).
@<|VectorFunctionSet| class declaration@>=
class VectorFunctionSet {
protected:@;
std::vector<VectorFunction*> funcs;
bool first_shallow;
public:@;
VectorFunctionSet(const VectorFunction& f, int n);
VectorFunctionSet(VectorFunction& f, int n);
~VectorFunctionSet();
VectorFunction& getFunc(int i)
{@+ return *(funcs[i]);@+}
int getNum() const
{@+ return funcs.size(); @+}
};
@ This class wraps another |VectorFunction| to allow integration of a
function through normally distributed inputs. Namely, if one wants to
integrate
$${1\over\sqrt{(2\pi)^n\vert\Sigma\vert}}\int f(x)e^{-{1\over2}x^T\Sigma^{-1}x}{\rm d}x$$
then if we write $\Sigma=AA^T$ and $x=\sqrt{2}Ay$, we get integral
$${1\over\sqrt{(2\pi)^n\vert\Sigma\vert}}
\int f\left(\sqrt{2}Ay\right)e^{-y^Ty}\sqrt{2^n}\vert A\vert{\rm d}y=
{1\over\sqrt{\pi^n}}\int f\left(\sqrt{2}Ay\right)e^{-y^Ty}{\rm d}y,$$
which means that a given function $f$ we have to wrap to yield a function
$$g(y)={1\over\sqrt{\pi^n}}f\left(\sqrt{2}Ay\right).$$
This is exactly what this class is doing. This transformation is
useful since the Gauss--Hermite points and weights are defined for
weighting function $e^{-y^2}$, so this transformation allows using
Gauss--Hermite quadratures seemlessly in a context of integration through
normally distributed inputs.
The class maintains a pointer to the function $f$. When the object is
constructed by the first constructor, the $f$ is not copied. If the
object of this class is copied, then $f$ is copied and we need to
remember to destroy it in the desctructor; hence |delete_flag|. The
second constructor takes a pointer to the function and differs from
the first only by setting |delete_flag| to |true|.
@<|GaussConverterFunction| class declaration@>=
class GaussConverterFunction : public VectorFunction {
protected:@;
VectorFunction* func;
bool delete_flag;
GeneralMatrix A;
double multiplier;
public:@;
GaussConverterFunction(VectorFunction& f, const GeneralMatrix& vcov);
GaussConverterFunction(VectorFunction* f, const GeneralMatrix& vcov);
GaussConverterFunction(const GaussConverterFunction& f);
virtual ~GaussConverterFunction()
{@+ if (delete_flag) delete func; @+}
virtual VectorFunction* clone() const
{@+ return new GaussConverterFunction(*this);@+}
virtual void eval(const Vector& point, const ParameterSignal& sig, Vector& out);
private:@;
double calcMultiplier() const;
void calcCholeskyFactor(const GeneralMatrix& vcov);
};
@ End of {\tt vector\_function.h} file

View File

@ -1,6 +1,6 @@
noinst_PROGRAMS = quadrature-points
quadrature_points_SOURCES = quadrature-points.cpp
quadrature_points_CPPFLAGS = -I../.. -I../../sylv/cc -I../../integ/cc -I../../tl/cc
quadrature_points_CXXFLAGS = $(AM_CXXFLAGS) $(PTHREAD_CFLAGS)
quadrature_points_LDADD = ../cc/libinteg.a ../../tl/cc/libtl.a ../../parser/cc/libparser.a ../../sylv/cc/libsylv.a ../../utils/cc/libutils.a $(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS) $(FLIBS) $(PTHREAD_LIBS)
quadrature_points_SOURCES = quadrature-points.cc
quadrature_points_CPPFLAGS = -I../.. -I../../sylv/cc -I../../integ/cc -I../../tl/cc -I../../utils/cc
quadrature_points_CXXFLAGS = $(AM_CXXFLAGS) $(THREAD_CXXFLAGS)
quadrature_points_LDADD = ../cc/libinteg.a ../../tl/cc/libtl.a ../../parser/cc/libparser.a ../../sylv/cc/libsylv.a ../../utils/cc/libutils.a $(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS) $(FLIBS)

View File

@ -0,0 +1,240 @@
/*
* Copyright © 2008-2011 Ondra Kamenik
* 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/>.
*/
#include "parser/cc/matrix_parser.hh"
#include "utils/cc/exception.hh"
#include "sylv/cc/GeneralMatrix.hh"
#include "sylv/cc/Vector.hh"
#include "sylv/cc/SymSchurDecomp.hh"
#include "sylv/cc/SylvException.hh"
#include "integ/cc/quadrature.hh"
#include "integ/cc/smolyak.hh"
#include "integ/cc/product.hh"
#include <getopt.h>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>
#include <memory>
#include <string>
struct QuadParams
{
std::string outname;
std::string vcovname;
int max_level{3};
double discard_weight{0.0};
QuadParams(int argc, char **argv);
void check_consistency() const;
private:
enum class opt {max_level, discard_weight, vcov};
};
QuadParams::QuadParams(int argc, char **argv)
{
if (argc == 1)
{
// Print the help and exit
std::cerr << "Usage: " << argv[0] << " [--max-level INTEGER] [--discard-weight FLOAT] [--vcov FILENAME] OUTPUT_FILENAME" << std::endl;
std::exit(EXIT_FAILURE);
}
outname = argv[argc-1];
argc--;
struct option const opts [] = {
{"max-level", required_argument, nullptr, static_cast<int>(opt::max_level)},
{"discard-weight", required_argument, nullptr, static_cast<int>(opt::discard_weight)},
{"vcov", required_argument, nullptr, static_cast<int>(opt::vcov)},
{nullptr, 0, nullptr, 0}
};
int ret;
int index;
while (-1 != (ret = getopt_long(argc, argv, "", opts, &index)))
{
if (ret == '?')
{
std::cerr << "Unknown option, ignored\n";
continue;
}
switch (static_cast<opt>(ret))
{
case opt::max_level:
try
{
max_level = std::stoi(optarg);
}
catch (const std::invalid_argument &e)
{
std::cerr << "Couldn't parse integer " << optarg << ", ignored" << std::endl;
}
break;
case opt::discard_weight:
try
{
discard_weight = std::stod(optarg);
}
catch (const std::invalid_argument &e)
{
std::cerr << "Couldn't parse float " << optarg << ", ignored" << std::endl;
}
break;
case opt::vcov:
vcovname = optarg;
break;
}
}
check_consistency();
}
void
QuadParams::check_consistency() const
{
if (outname.empty())
{
std::cerr << "Error: output name not set" << std::endl;
std::exit(EXIT_FAILURE);
}
if (vcovname.empty())
{
std::cerr << "Error: vcov file name not set" << std::endl;
std::exit(EXIT_FAILURE);
}
}
int
main(int argc, char **argv)
{
QuadParams params(argc, argv);
// Open output file for writing
std::ofstream fout{params.outname, std::ios::out | std::ios::trunc};
if (fout.fail())
{
std::cerr << "Could not open " << params.outname << " for writing" << std::endl;
std::exit(EXIT_FAILURE);
}
try
{
std::ifstream f{params.vcovname};
std::ostringstream buffer;
buffer << f.rdbuf();
std::string contents{buffer.str()};
// Parse the vcov matrix
ogp::MatrixParser mp;
mp.parse(contents);
if (mp.nrows() != mp.ncols())
throw ogu::Exception(__FILE__, __LINE__,
"VCOV matrix not square");
// And put to the GeneralMatrix
GeneralMatrix vcov(mp.nrows(), mp.ncols());
vcov.zeros();
for (ogp::MPIterator it = mp.begin(); it != mp.end(); ++it)
vcov.get(it.row(), it.col()) = *it;
// Calculate the factor A of vcov, so that A·Aᵀ=VCOV
GeneralMatrix A(vcov.nrows(), vcov.nrows());
SymSchurDecomp ssd(vcov);
ssd.getFactor(A);
// Construct Gauss-Hermite quadrature
GaussHermite ghq;
// Construct Smolyak quadrature
int level = params.max_level;
SmolyakQuadrature sq(vcov.nrows(), level, ghq);
std::cout << "Dimension: " << vcov.nrows() << std::endl
<< "Maximum level: " << level << std::endl
<< "Total number of nodes: " << sq.numEvals(level) << std::endl;
// Put the points to the vector
std::vector<std::unique_ptr<Vector>> points;
for (smolpit qit = sq.start(level); qit != sq.end(level); ++qit)
points.push_back(std::make_unique<Vector>(const_cast<const Vector &>(qit.point())));
// Sort and uniq
std::sort(points.begin(), points.end(), [](auto &a, auto &b) { return a.get() < b.get(); });
auto new_end = std::unique(points.begin(), points.end());
points.erase(new_end, points.end());
std::cout << "Duplicit nodes removed: " << static_cast<unsigned long>(sq.numEvals(level)-points.size())
<< std::endl;
// Calculate weights and mass
double mass = 0.0;
std::vector<double> weights;
for (auto & point : points)
{
weights.push_back(std::exp(-point->dot(*point)));
mass += weights.back();
}
// Calculate discarded mass
double discard_mass = 0.0;
for (double weight : weights)
if (weight/mass < params.discard_weight)
discard_mass += weight;
std::cout << "Total mass discarded: " << std::fixed << discard_mass/mass << std::endl;
// Dump the results
int npoints = 0;
double upscale_weight = 1/(mass-discard_mass);
Vector x(vcov.nrows());
fout << std::setprecision(16);
for (int i = 0; i < static_cast<int>(weights.size()); i++)
if (weights[i]/mass >= params.discard_weight)
{
// Print the upscaled weight
fout << std::setw(20) << upscale_weight*weights[i];
// Multiply point with the factor A and √2
A.multVec(0.0, x, std::sqrt(2.), *(points[i]));
// Print the coordinates
for (int j = 0; j < x.length(); j++)
fout << ' ' << std::setw(20) << x[j];
fout << std::endl;
npoints++;
}
std::cout << "Final number of points: " << npoints << std::endl;
fout.close();
}
catch (const SylvException &e)
{
e.printMessage();
return EXIT_FAILURE;
}
catch (const ogu::Exception &e)
{
e.print();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -1,192 +0,0 @@
// Copyright (C) 2008-2011, Ondra Kamenik
#include "parser/cc/matrix_parser.h"
#include "utils/cc/memory_file.h"
#include "utils/cc/exception.h"
#include "sylv/cc/GeneralMatrix.h"
#include "sylv/cc/Vector.h"
#include "sylv/cc/SymSchurDecomp.h"
#include "sylv/cc/SylvException.h"
#include "integ/cc/quadrature.h"
#include "integ/cc/smolyak.h"
#include "integ/cc/product.h"
#include <getopt.h>
#include <cstdio>
#include <cmath>
struct QuadParams {
const char* outname;
const char* vcovname;
int max_level;
double discard_weight;
QuadParams(int argc, char** argv);
void check_consistency() const;
private:
enum {opt_max_level, opt_discard_weight, opt_vcov};
};
QuadParams::QuadParams(int argc, char** argv)
: outname(NULL), vcovname(NULL), max_level(3), discard_weight(0.0)
{
if (argc == 1) {
// print the help and exit
exit(1);
}
outname = argv[argc-1];
argc--;
struct option const opts [] = {
{"max-level", required_argument, NULL, opt_max_level},
{"discard-weight", required_argument, NULL, opt_discard_weight},
{"vcov", required_argument, NULL, opt_vcov},
{NULL, 0, NULL, 0}
};
int ret;
int index;
while (-1 != (ret = getopt_long(argc, argv, "", opts, &index))) {
switch (ret) {
case opt_max_level:
if (1 != sscanf(optarg, "%d", &max_level))
fprintf(stderr, "Couldn't parse integer %s, ignored\n", optarg);
break;
case opt_discard_weight:
if (1 != sscanf(optarg, "%lf", &discard_weight))
fprintf(stderr, "Couldn't parse float %s, ignored\n", optarg);
break;
case opt_vcov:
vcovname = optarg;
break;
}
}
check_consistency();
}
void QuadParams::check_consistency() const
{
if (outname == NULL) {
fprintf(stderr, "Error: output name not set\n");
exit(1);
}
if (vcovname == NULL) {
fprintf(stderr, "Error: vcov file name not set\n");
exit(1);
}
}
/** Utility class for ordering pointers to vectors according their
* ordering. */
struct OrderVec {
bool operator()(const Vector* a, const Vector* b) const
{return *a < *b;}
};
int main(int argc, char** argv)
{
QuadParams params(argc, argv);
// open output file for writing
FILE* fout;
if (NULL == (fout=fopen(params.outname, "w"))) {
fprintf(stderr, "Could not open %s for writing\n", params.outname);
exit(1);
}
try {
// open memory file for vcov
ogu::MemoryFile vcov_mf(params.vcovname);
// parse the vcov matrix
ogp::MatrixParser mp;
mp.parse(vcov_mf.length(), vcov_mf.base());
if (mp.nrows() != mp.ncols())
throw ogu::Exception(__FILE__,__LINE__,
"VCOV matrix not square");
// and put to the GeneralMatrix
GeneralMatrix vcov(mp.nrows(), mp.ncols());
vcov.zeros();
for (ogp::MPIterator it = mp.begin(); it != mp.end(); ++it)
vcov.get(it.row(), it.col()) = *it;
// calculate the factor A of vcov, so that A*A^T=VCOV
GeneralMatrix A(vcov.numRows(), vcov.numRows());
SymSchurDecomp ssd(vcov);
ssd.getFactor(A);
// construct Gauss-Hermite quadrature
GaussHermite ghq;
// construct Smolyak quadrature
int level = params.max_level;
SmolyakQuadrature sq(vcov.numRows(), level, ghq);
printf("Dimension: %d\n", vcov.numRows());
printf("Maximum level: %d\n", level);
printf("Total number of nodes: %d\n", sq.numEvals(level));
// put the points to the vector
std::vector<Vector*> points;
for (smolpit qit = sq.start(level); qit != sq.end(level); ++qit)
points.push_back(new Vector((const Vector&)qit.point()));
// sort and uniq
OrderVec ordvec;
std::sort(points.begin(), points.end(), ordvec);
std::vector<Vector*>::iterator new_end = std::unique(points.begin(), points.end());
for (std::vector<Vector*>::iterator it = new_end; it != points.end(); ++it)
delete *it;
points.erase(new_end, points.end());
printf("Duplicit nodes removed: %lu\n", (unsigned long) (sq.numEvals(level)-points.size()));
// calculate weights and mass
double mass = 0.0;
std::vector<double> weights;
for (int i = 0; i < (int)points.size(); i++) {
weights.push_back(std::exp(-points[i]->dot(*(points[i]))));
mass += weights.back();
}
// calculate discarded mass
double discard_mass = 0.0;
for (int i = 0; i < (int)weights.size(); i++)
if (weights[i]/mass < params.discard_weight)
discard_mass += weights[i];
printf("Total mass discarded: %f\n", discard_mass/mass);
// dump the results
int npoints = 0;
double upscale_weight = 1/(mass-discard_mass);
Vector x(vcov.numRows());
for (int i = 0; i < (int)weights.size(); i++)
if (weights[i]/mass >= params.discard_weight) {
// print the upscaled weight
fprintf(fout, "%20.16g", upscale_weight*weights[i]);
// multiply point with the factor A and sqrt(2)
A.multVec(0.0, x, std::sqrt(2.), *(points[i]));
// print the coordinates
for (int j = 0; j < x.length(); j++)
fprintf(fout, " %20.16g", x[j]);
fprintf(fout, "\n");
npoints++;
}
printf("Final number of points: %d\n", npoints);
fclose(fout);
} catch (const SylvException& e) {
e.printMessage();
return 1;
} catch (const ogu::Exception& e) {
e.print();
return 1;
}
return 0;
}

View File

@ -1,10 +1,10 @@
check_PROGRAMS = tests
tests_SOURCES = tests.cpp
tests_CPPFLAGS = -I../cc -I../../tl/cc -I../../sylv/cc -I$(top_srcdir)/mex/sources
tests_CXXFLAGS = $(AM_CXXFLAGS) $(PTHREAD_CFLAGS)
tests_SOURCES = tests.cc
tests_CPPFLAGS = -I../cc -I../../tl/cc -I../../sylv/cc -I../../utils/cc -I$(top_srcdir)/mex/sources
tests_CXXFLAGS = $(AM_CXXFLAGS) $(THREAD_CXXFLAGS)
tests_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS_MATIO)
tests_LDADD = ../../tl/cc/libtl.a ../../sylv/cc/libsylv.a ../cc/libinteg.a $(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS) $(FLIBS) $(PTHREAD_LIBS) $(LIBADD_MATIO)
tests_LDADD = ../../sylv/cc/libsylv.a ../cc/libinteg.a ../../tl/cc/libtl.a ../../utils/cc/libutils.a $(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS) $(FLIBS) $(LIBADD_MATIO)
check-local:
./tests

View File

@ -0,0 +1,550 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
#include "GeneralMatrix.hh"
#include <dynlapack.h>
#include "SylvException.hh"
#include "rfs_tensor.hh"
#include "normal_moments.hh"
#include "vector_function.hh"
#include "quadrature.hh"
#include "smolyak.hh"
#include "product.hh"
#include "quasi_mcarlo.hh"
#include <iomanip>
#include <chrono>
#include <cmath>
#include <iostream>
#include <utility>
#include <array>
#include <memory>
#include <cstdlib>
/* Evaluates unfolded (Dx)ᵏ power, where x is a vector, D is a Cholesky factor
(lower triangular) */
class MomentFunction : public VectorFunction
{
GeneralMatrix D;
int k;
public:
MomentFunction(const GeneralMatrix &inD, int kk)
: VectorFunction(inD.nrows(), UFSTensor::calcMaxOffset(inD.nrows(), kk)),
D(inD), k(kk)
{
}
MomentFunction(const MomentFunction &func) = default;
std::unique_ptr<VectorFunction>
clone() const override
{
return std::make_unique<MomentFunction>(*this);
}
void eval(const Vector &point, const ParameterSignal &sig, Vector &out) override;
};
void
MomentFunction::eval(const Vector &point, const ParameterSignal &sig, Vector &out)
{
if (point.length() != indim() || out.length() != outdim())
{
std::cerr << "Wrong length of vectors in MomentFunction::eval" << std::endl;
std::exit(EXIT_FAILURE);
}
Vector y(point);
y.zeros();
D.multaVec(y, point);
URSingleTensor ypow(y, k);
out.zeros();
out.add(1.0, ypow.getData());
}
class TensorPower : public VectorFunction
{
int k;
public:
TensorPower(int nvar, int kk)
: VectorFunction(nvar, UFSTensor::calcMaxOffset(nvar, kk)), k(kk)
{
}
TensorPower(const TensorPower &func) = default;
std::unique_ptr<VectorFunction>
clone() const override
{
return std::make_unique<TensorPower>(*this);
}
void eval(const Vector &point, const ParameterSignal &sig, Vector &out) override;
};
void
TensorPower::eval(const Vector &point, const ParameterSignal &sig, Vector &out)
{
if (point.length() != indim() || out.length() != outdim())
{
std::cerr << "Wrong length of vectors in TensorPower::eval" << std::endl;
std::exit(EXIT_FAILURE);
}
URSingleTensor ypow(point, k);
out.zeros();
out.add(1.0, ypow.getData());
}
/* Evaluates (1+1/d)ᵈ(x₁·…·x_d)^(1/d), its integral over [0,1]ᵈ
is 1.0, and its variation grows exponentially */
class Function1 : public VectorFunction
{
int dim;
public:
Function1(int d)
: VectorFunction(d, 1), dim(d)
{
}
Function1(const Function1 &f)
: VectorFunction(f.indim(), f.outdim()), dim(f.dim)
{
}
std::unique_ptr<VectorFunction>
clone() const override
{
return std::make_unique<Function1>(*this);
}
void eval(const Vector &point, const ParameterSignal &sig, Vector &out) override;
};
void
Function1::eval(const Vector &point, const ParameterSignal &sig, Vector &out)
{
if (point.length() != dim || out.length() != 1)
{
std::cerr << "Wrong length of vectors in Function1::eval" << std::endl;
std::exit(EXIT_FAILURE);
}
double r = 1;
for (int i = 0; i < dim; i++)
r *= point[i];
r = pow(r, 1.0/dim);
r *= pow(1.0 + 1.0/dim, static_cast<double>(dim));
out[0] = r;
}
// Evaluates Function1 but with transformation xᵢ=0.5(yᵢ+1)
// This makes the new function integrate over [1,1]ᵈ to 1.0
class Function1Trans : public Function1
{
public:
Function1Trans(int d)
: Function1(d)
{
}
Function1Trans(const Function1Trans &func) = default;
std::unique_ptr<VectorFunction>
clone() const override
{
return std::make_unique<Function1Trans>(*this);
}
void eval(const Vector &point, const ParameterSignal &sig, Vector &out) override;
};
void
Function1Trans::eval(const Vector &point, const ParameterSignal &sig, Vector &out)
{
Vector p(point.length());
for (int i = 0; i < p.length(); i++)
p[i] = 0.5*(point[i]+1);
Function1::eval(p, sig, out);
out.mult(pow(0.5, indim()));
}
/* WallTimer class. Constructor saves the wall time, destructor cancels the
current time from the saved, and prints the message with time information */
class WallTimer
{
std::string mes;
std::chrono::time_point<std::chrono::high_resolution_clock> start;
bool new_line;
public:
WallTimer(std::string m, bool nl = true)
: mes{m}, start{std::chrono::high_resolution_clock::now()}, new_line{nl}
{
}
~WallTimer()
{
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = end - start;
std::cout << mes << std::setw(8) << std::setprecision(4) << duration.count();
if (new_line)
std::cout << std::endl;
}
};
/****************************************************/
/* declaration of TestRunnable class */
/****************************************************/
class TestRunnable
{
public:
const std::string name;
int dim; // dimension of the solved problem
int nvar; // number of variables of the solved problem
TestRunnable(std::string name_arg, int d, int nv)
: name{move(name_arg)}, dim(d), nvar(nv)
{
}
virtual ~TestRunnable() = default;
bool test() const;
virtual bool run() const = 0;
protected:
static bool smolyak_normal_moments(const GeneralMatrix &m, int imom, int level);
static bool product_normal_moments(const GeneralMatrix &m, int imom, int level);
static bool qmc_normal_moments(const GeneralMatrix &m, int imom, int level);
static bool smolyak_product_cube(const VectorFunction &func, const Vector &res,
double tol, int level);
static bool qmc_cube(const VectorFunction &func, double res, double tol, int level);
};
bool
TestRunnable::test() const
{
std::cout << "Running test <" << name << ">" << std::endl;
bool passed;
{
WallTimer tim("Wall clock time ", false);
passed = run();
}
if (passed)
{
std::cout << "............................ passed" << std::endl << std::endl;
return passed;
}
else
{
std::cout << "............................ FAILED" << std::endl << std::endl;
return passed;
}
}
/****************************************************/
/* definition of TestRunnable static methods */
/****************************************************/
bool
TestRunnable::smolyak_normal_moments(const GeneralMatrix &m, int imom, int level)
{
// First make m·mᵀ and then Cholesky factor
GeneralMatrix msq(m * transpose(m));
// Make vector function
int dim = m.nrows();
TensorPower tp(dim, imom);
GaussConverterFunction func(tp, msq);
// Smolyak quadrature
Vector smol_out(UFSTensor::calcMaxOffset(dim, imom));
{
WallTimer tim("\tSmolyak quadrature time: ");
GaussHermite gs;
SmolyakQuadrature quad(dim, level, gs);
quad.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, smol_out);
std::cout << "\tNumber of Smolyak evaluations: " << quad.numEvals(level) << std::endl;
}
// Check against theoretical moments
UNormalMoments moments(imom, msq);
smol_out.add(-1.0, moments.get(Symmetry{imom}).getData());
std::cout << "\tError: " << std::setw(16) << std::setprecision(12) << smol_out.getMax() << std::endl;
return smol_out.getMax() < 1.e-7;
}
bool
TestRunnable::product_normal_moments(const GeneralMatrix &m, int imom, int level)
{
// First make m·mᵀ and then Cholesky factor
GeneralMatrix msq(m * transpose(m));
// Make vector function
int dim = m.nrows();
TensorPower tp(dim, imom);
GaussConverterFunction func(tp, msq);
// Product quadrature
Vector prod_out(UFSTensor::calcMaxOffset(dim, imom));
{
WallTimer tim("\tProduct quadrature time: ");
GaussHermite gs;
ProductQuadrature quad(dim, gs);
quad.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, prod_out);
std::cout << "\tNumber of product evaluations: " << quad.numEvals(level) << std::endl;
}
// Check against theoretical moments
UNormalMoments moments(imom, msq);
prod_out.add(-1.0, moments.get(Symmetry{imom}).getData());
std::cout << "\tError: " << std::setw(16) << std::setprecision(12) << prod_out.getMax() << std::endl;
return prod_out.getMax() < 1.e-7;
}
bool
TestRunnable::smolyak_product_cube(const VectorFunction &func, const Vector &res,
double tol, int level)
{
if (res.length() != func.outdim())
{
std::cerr << "Incompatible dimensions of check value and function." << std::endl;
std::exit(EXIT_FAILURE);
}
GaussLegendre glq;
Vector out(func.outdim());
double smol_error;
double prod_error;
{
WallTimer tim("\tSmolyak quadrature time: ");
SmolyakQuadrature quad(func.indim(), level, glq);
quad.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, out);
out.add(-1.0, res);
smol_error = out.getMax();
std::cout << "\tNumber of Smolyak evaluations: " << quad.numEvals(level) << std::endl;
std::cout << "\tError: " << std::setw(16) << std::setprecision(12) << smol_error << std::endl;
}
{
WallTimer tim("\tProduct quadrature time: ");
ProductQuadrature quad(func.indim(), glq);
quad.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, out);
out.add(-1.0, res);
prod_error = out.getMax();
std::cout << "\tNumber of product evaluations: " << quad.numEvals(level) << std::endl;
std::cout << "\tError: " << std::setw(16) << std::setprecision(12) << prod_error << std::endl;
}
return smol_error < tol && prod_error < tol;
}
bool
TestRunnable::qmc_cube(const VectorFunction &func, double res, double tol, int level)
{
Vector r(1);
double error1;
{
WallTimer tim("\tQuasi-Monte Carlo (Warnock scrambling) time: ");
WarnockPerScheme wps;
QMCarloCubeQuadrature qmc(func.indim(), level, wps);
qmc.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, r);
error1 = std::max(res - r[0], r[0] - res);
std::cout << "\tQuasi-Monte Carlo (Warnock scrambling) error: " << std::setw(16) << std::setprecision(12) << error1 << std::endl;
}
double error2;
{
WallTimer tim("\tQuasi-Monte Carlo (reverse scrambling) time: ");
ReversePerScheme rps;
QMCarloCubeQuadrature qmc(func.indim(), level, rps);
qmc.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, r);
error2 = std::max(res - r[0], r[0] - res);
std::cout << "\tQuasi-Monte Carlo (reverse scrambling) error: " << std::setw(16) << std::setprecision(12) << error2 << std::endl;
}
double error3;
{
WallTimer tim("\tQuasi-Monte Carlo (no scrambling) time: ");
IdentityPerScheme ips;
QMCarloCubeQuadrature qmc(func.indim(), level, ips);
qmc.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, r);
error3 = std::max(res - r[0], r[0] - res);
std::cout << "\tQuasi-Monte Carlo (no scrambling) error: " << std::setw(16) << std::setprecision(12) << error3 << std::endl;
}
return error1 < tol && error2 < tol && error3 < tol;
}
/****************************************************/
/* definition of TestRunnable subclasses */
/****************************************************/
class SmolyakNormalMom1 : public TestRunnable
{
public:
SmolyakNormalMom1()
: TestRunnable("Smolyak normal moments (dim=2, level=4, order=4)", 4, 2)
{
}
bool
run() const override
{
GeneralMatrix m(2, 2);
m.zeros();
m.get(0, 0) = 1;
m.get(1, 1) = 1;
return smolyak_normal_moments(m, 4, 4);
}
};
class SmolyakNormalMom2 : public TestRunnable
{
public:
SmolyakNormalMom2()
: TestRunnable("Smolyak normal moments (dim=3, level=8, order=8)", 8, 3)
{
}
bool
run() const override
{
GeneralMatrix m(3, 3);
m.zeros();
m.get(0, 0) = 1;
m.get(0, 2) = 0.5;
m.get(1, 1) = 1;
m.get(1, 0) = 0.5;
m.get(2, 2) = 2;
m.get(2, 1) = 4;
return smolyak_normal_moments(m, 8, 8);
}
};
class ProductNormalMom1 : public TestRunnable
{
public:
ProductNormalMom1()
: TestRunnable("Product normal moments (dim=2, level=4, order=4)", 4, 2)
{
}
bool
run() const override
{
GeneralMatrix m(2, 2);
m.zeros();
m.get(0, 0) = 1;
m.get(1, 1) = 1;
return product_normal_moments(m, 4, 4);
}
};
class ProductNormalMom2 : public TestRunnable
{
public:
ProductNormalMom2()
: TestRunnable("Product normal moments (dim=3, level=8, order=8)", 8, 3)
{
}
bool
run() const override
{
GeneralMatrix m(3, 3);
m.zeros();
m.get(0, 0) = 1;
m.get(0, 2) = 0.5;
m.get(1, 1) = 1;
m.get(1, 0) = 0.5;
m.get(2, 2) = 2;
m.get(2, 1) = 4;
return product_normal_moments(m, 8, 8);
}
};
// Note that here we pass 1,1 to tls since smolyak has its own PascalTriangle
class F1GaussLegendre : public TestRunnable
{
public:
F1GaussLegendre()
: TestRunnable("Function1 Gauss-Legendre (dim=6, level=13", 1, 1)
{
}
bool
run() const override
{
Function1Trans f1(6);
Vector res(1);
res[0] = 1.0;
return smolyak_product_cube(f1, res, 1e-2, 13);
}
};
class F1QuasiMCarlo : public TestRunnable
{
public:
F1QuasiMCarlo()
: TestRunnable("Function1 Quasi-Monte Carlo (dim=6, level=1000000)", 1, 1)
{
}
bool
run() const override
{
Function1 f1(6);
return qmc_cube(f1, 1.0, 1.e-4, 1000000);
}
};
int
main()
{
std::vector<std::unique_ptr<TestRunnable>> all_tests;
// Fill in vector of all tests
all_tests.push_back(std::make_unique<SmolyakNormalMom1>());
all_tests.push_back(std::make_unique<SmolyakNormalMom2>());
all_tests.push_back(std::make_unique<ProductNormalMom1>());
all_tests.push_back(std::make_unique<ProductNormalMom2>());
all_tests.push_back(std::make_unique<F1GaussLegendre>());
all_tests.push_back(std::make_unique<F1QuasiMCarlo>());
// Find maximum dimension and maximum nvar
int dmax = 0;
int nvmax = 0;
for (const auto &test : all_tests)
{
dmax = std::max(dmax, test->dim);
nvmax = std::max(nvmax, test->nvar);
}
TLStatic::init(dmax, nvmax); // initialize library
// Launch the tests
int success = 0;
for (const auto &test : all_tests)
{
try
{
if (test->test())
success++;
}
catch (const TLException &e)
{
std::cout << "Caught TL exception in <" << test->name << ">:" << std::endl;
e.print();
}
catch (SylvException &e)
{
std::cout << "Caught Sylv exception in <" << test->name << ">:" << std::endl;
e.printMessage();
}
}
int nfailed = all_tests.size() - success;
std::cout << "There were " << nfailed << " tests that failed out of "
<< all_tests.size() << " tests run." << std::endl;
if (nfailed)
return EXIT_FAILURE;
else
return EXIT_SUCCESS;
}

View File

@ -1,544 +0,0 @@
/* $Id: tests.cpp 431 2005-08-16 15:41:01Z kamenik $ */
/* Copyright 2005, Ondra Kamenik */
#include "GeneralMatrix.h"
#include <dynlapack.h>
#include "SylvException.h"
#include "rfs_tensor.h"
#include "normal_moments.h"
#include "vector_function.h"
#include "quadrature.h"
#include "smolyak.h"
#include "product.h"
#include "quasi_mcarlo.h"
#include <cstdio>
#include <cstring>
#include <sys/time.h>
#include <cmath>
const int num_threads = 2; // does nothing if DEBUG defined
// evaluates unfolded (Dx)^k power, where x is a vector, D is a
// Cholesky factor (lower triangular)
class MomentFunction : public VectorFunction {
GeneralMatrix D;
int k;
public:
MomentFunction(const GeneralMatrix& inD, int kk)
: VectorFunction(inD.numRows(), UFSTensor::calcMaxOffset(inD.numRows(), kk)),
D(inD), k(kk) {}
MomentFunction(const MomentFunction& func)
: VectorFunction(func), D(func.D), k(func.k) {}
VectorFunction* clone() const
{return new MomentFunction(*this);}
void eval(const Vector& point, const ParameterSignal& sig, Vector& out);
};
void MomentFunction::eval(const Vector& point, const ParameterSignal& sig, Vector& out)
{
if (point.length() != indim() || out.length() != outdim()) {
printf("Wrong length of vectors in MomentFunction::eval\n");
exit(1);
}
Vector y(point);
y.zeros();
D.multaVec(y, point);
URSingleTensor ypow(y, k);
out.zeros();
out.add(1.0, ypow.getData());
}
class TensorPower : public VectorFunction {
int k;
public:
TensorPower(int nvar, int kk)
: VectorFunction(nvar, UFSTensor::calcMaxOffset(nvar, kk)), k(kk) {}
TensorPower(const TensorPower& func)
: VectorFunction(func), k(func.k) {}
VectorFunction* clone() const
{return new TensorPower(*this);}
void eval(const Vector& point, const ParameterSignal& sig, Vector& out);
};
void TensorPower::eval(const Vector& point, const ParameterSignal& sig, Vector& out)
{
if (point.length() != indim() || out.length() != outdim()) {
printf("Wrong length of vectors in TensorPower::eval\n");
exit(1);
}
URSingleTensor ypow(point, k);
out.zeros();
out.add(1.0, ypow.getData());
}
// evaluates (1+1/d)^d*(x_1*...*x_d)^(1/d), its integral over <0,1>^d
// is 1.0, and its variation grows exponetially
// d = dim
class Function1 : public VectorFunction {
int dim;
public:
Function1(int d)
: VectorFunction(d, 1), dim(d) {}
Function1(const Function1& f)
: VectorFunction(f.indim(), f.outdim()), dim(f.dim) {}
VectorFunction* clone() const
{return new Function1(*this);}
virtual void eval(const Vector& point, const ParameterSignal& sig, Vector& out);
};
void Function1::eval(const Vector& point, const ParameterSignal& sig, Vector& out)
{
if (point.length() != dim || out.length() != 1) {
printf("Wrong length of vectors in Function1::eval\n");
exit(1);
}
double r = 1;
for (int i = 0; i < dim; i++)
r *= point[i];
r = pow(r, 1.0/dim);
r *= pow(1.0 + 1.0/dim, (double)dim);
out[0] = r;
}
// evaluates Function1 but with transformation x_i=0.5(y_i+1)
// this makes the new function integrate over <-1,1>^d to 1.0
class Function1Trans : public Function1 {
public:
Function1Trans(int d)
: Function1(d) {}
Function1Trans(const Function1Trans& func)
: Function1(func) {}
VectorFunction* clone() const
{return new Function1Trans(*this);}
virtual void eval(const Vector& point, const ParameterSignal& sig, Vector& out);
};
void Function1Trans::eval(const Vector& point, const ParameterSignal& sig, Vector& out)
{
Vector p(point.length());
for (int i = 0; i < p.length(); i++)
p[i] = 0.5*(point[i]+1);
Function1::eval(p, sig, out);
out.mult(pow(0.5,indim()));
}
// WallTimer class. Constructor saves the wall time, destructor
// cancels the current time from the saved, and prints the message
// with time information
class WallTimer {
char mes[100];
struct timeval start;
bool new_line;
public:
WallTimer(const char* m, bool nl = true)
{strcpy(mes, m);new_line = nl; gettimeofday(&start, NULL);}
~WallTimer()
{
struct timeval end;
gettimeofday(&end, NULL);
printf("%s%8.4g", mes,
end.tv_sec-start.tv_sec + (end.tv_usec-start.tv_usec)*1.0e-6);
if (new_line)
printf("\n");
}
};
/****************************************************/
/* declaration of TestRunnable class */
/****************************************************/
class TestRunnable {
char name[100];
public:
int dim; // dimension of the solved problem
int nvar; // number of variable of the solved problem
TestRunnable(const char* n, int d, int nv)
: dim(d), nvar(nv)
{strncpy(name, n, 100);}
bool test() const;
virtual bool run() const =0;
const char* getName() const
{return name;}
protected:
static bool smolyak_normal_moments(const GeneralMatrix& m, int imom, int level);
static bool product_normal_moments(const GeneralMatrix& m, int imom, int level);
static bool qmc_normal_moments(const GeneralMatrix& m, int imom, int level);
static bool smolyak_product_cube(const VectorFunction& func, const Vector& res,
double tol, int level);
static bool qmc_cube(const VectorFunction& func, double res, double tol, int level);
};
bool TestRunnable::test() const
{
printf("Running test <%s>\n",name);
bool passed;
{
WallTimer tim("Wall clock time ", false);
passed = run();
}
if (passed) {
printf("............................ passed\n\n");
return passed;
} else {
printf("............................ FAILED\n\n");
return passed;
}
}
/****************************************************/
/* definition of TestRunnable static methods */
/****************************************************/
bool TestRunnable::smolyak_normal_moments(const GeneralMatrix& m, int imom, int level)
{
// first make m*m' and then Cholesky factor
GeneralMatrix mtr(m, "transpose");
GeneralMatrix msq(m, mtr);
// make vector function
int dim = m.numRows();
TensorPower tp(dim, imom);
GaussConverterFunction func(tp, msq);
// smolyak quadrature
Vector smol_out(UFSTensor::calcMaxOffset(dim, imom));
{
WallTimer tim("\tSmolyak quadrature time: ");
GaussHermite gs;
SmolyakQuadrature quad(dim, level, gs);
quad.integrate(func, level, num_threads, smol_out);
printf("\tNumber of Smolyak evaluations: %d\n", quad.numEvals(level));
}
// check against theoretical moments
UNormalMoments moments(imom, msq);
smol_out.add(-1.0, (moments.get(Symmetry(imom)))->getData());
printf("\tError: %16.12g\n", smol_out.getMax());
return smol_out.getMax() < 1.e-7;
}
bool TestRunnable::product_normal_moments(const GeneralMatrix& m, int imom, int level)
{
// first make m*m' and then Cholesky factor
GeneralMatrix mtr(m, "transpose");
GeneralMatrix msq(m, mtr);
// make vector function
int dim = m.numRows();
TensorPower tp(dim, imom);
GaussConverterFunction func(tp, msq);
// product quadrature
Vector prod_out(UFSTensor::calcMaxOffset(dim, imom));
{
WallTimer tim("\tProduct quadrature time: ");
GaussHermite gs;
ProductQuadrature quad(dim, gs);
quad.integrate(func, level, num_threads, prod_out);
printf("\tNumber of product evaluations: %d\n", quad.numEvals(level));
}
// check against theoretical moments
UNormalMoments moments(imom, msq);
prod_out.add(-1.0, (moments.get(Symmetry(imom)))->getData());
printf("\tError: %16.12g\n", prod_out.getMax());
return prod_out.getMax() < 1.e-7;
}
bool TestRunnable::qmc_normal_moments(const GeneralMatrix& m, int imom, int level)
{
// first make m*m' and then Cholesky factor
GeneralMatrix mtr(m, "transpose");
GeneralMatrix msq(m, mtr);
GeneralMatrix mchol(msq);
int rows = mchol.numRows();
for (int i = 0; i < rows; i++)
for (int j = i+1; j < rows; j++)
mchol.get(i,j) = 0.0;
int info;
dpotrf("L", &rows, mchol.base(), &rows, &info);
// make vector function
MomentFunction func(mchol, imom);
// permutation schemes
WarnockPerScheme wps;
ReversePerScheme rps;
IdentityPerScheme ips;
PermutationScheme* scheme[] = {&wps, &rps, &ips};
const char* labs[] = {"Warnock", "Reverse", "Identity"};
// theoretical result
int dim = mchol.numRows();
UNormalMoments moments(imom, msq);
Vector res((const Vector&)((moments.get(Symmetry(imom)))->getData()));
// quasi monte carlo normal quadrature
double max_error = 0.0;
Vector qmc_out(UFSTensor::calcMaxOffset(dim, imom));
for (int i = 0; i < 3; i++) {
{
char mes[100];
sprintf(mes, "\tQMC normal quadrature time %8s: ", labs[i]);
WallTimer tim(mes);
QMCarloNormalQuadrature quad(dim, level, *(scheme[i]));
quad.integrate(func, level, num_threads, qmc_out);
}
qmc_out.add(-1.0, res);
printf("\tError %8s: %16.12g\n", labs[i], qmc_out.getMax());
if (qmc_out.getMax() > max_error) {
max_error = qmc_out.getMax();
}
}
return max_error < 1.e-7;
}
bool TestRunnable::smolyak_product_cube(const VectorFunction& func, const Vector& res,
double tol, int level)
{
if (res.length() != func.outdim()) {
fprintf(stderr, "Incompatible dimensions of check value and function.\n");
exit(1);
}
GaussLegendre glq;
Vector out(func.outdim());
double smol_error;
double prod_error;
{
WallTimer tim("\tSmolyak quadrature time: ");
SmolyakQuadrature quad(func.indim(), level, glq);
quad.integrate(func, level, num_threads, out);
out.add(-1.0, res);
smol_error = out.getMax();
printf("\tNumber of Smolyak evaluations: %d\n", quad.numEvals(level));
printf("\tError: %16.12g\n", smol_error);
}
{
WallTimer tim("\tProduct quadrature time: ");
ProductQuadrature quad(func.indim(), glq);
quad.integrate(func, level, num_threads, out);
out.add(-1.0, res);
prod_error = out.getMax();
printf("\tNumber of product evaluations: %d\n", quad.numEvals(level));
printf("\tError: %16.12g\n", prod_error);
}
return smol_error < tol && prod_error < tol;
}
bool TestRunnable::qmc_cube(const VectorFunction& func, double res, double tol, int level)
{
Vector r(1);
double error1;
{
WallTimer tim("\tQuasi-Monte Carlo (Warnock scrambling) time: ");
WarnockPerScheme wps;
QMCarloCubeQuadrature qmc(func.indim(), level, wps);
// qmc.savePoints("warnock.txt", level);
qmc.integrate(func, level, num_threads, r);
error1 = std::max(res - r[0], r[0] - res);
printf("\tQuasi-Monte Carlo (Warnock scrambling) error: %16.12g\n",
error1);
}
double error2;
{
WallTimer tim("\tQuasi-Monte Carlo (reverse scrambling) time: ");
ReversePerScheme rps;
QMCarloCubeQuadrature qmc(func.indim(), level, rps);
// qmc.savePoints("reverse.txt", level);
qmc.integrate(func, level, num_threads, r);
error2 = std::max(res - r[0], r[0] - res);
printf("\tQuasi-Monte Carlo (reverse scrambling) error: %16.12g\n",
error2);
}
double error3;
{
WallTimer tim("\tQuasi-Monte Carlo (no scrambling) time: ");
IdentityPerScheme ips;
QMCarloCubeQuadrature qmc(func.indim(), level, ips);
// qmc.savePoints("identity.txt", level);
qmc.integrate(func, level, num_threads, r);
error3 = std::max(res - r[0], r[0] - res);
printf("\tQuasi-Monte Carlo (no scrambling) error: %16.12g\n",
error3);
}
return error1 < tol && error2 < tol && error3 < tol;
}
/****************************************************/
/* definition of TestRunnable subclasses */
/****************************************************/
class SmolyakNormalMom1 : public TestRunnable {
public:
SmolyakNormalMom1()
: TestRunnable("Smolyak normal moments (dim=2, level=4, order=4)", 4, 2) {}
bool run() const
{
GeneralMatrix m(2,2);
m.zeros(); m.get(0,0)=1; m.get(1,1)=1;
return smolyak_normal_moments(m, 4, 4);
}
};
class SmolyakNormalMom2 : public TestRunnable {
public:
SmolyakNormalMom2()
: TestRunnable("Smolyak normal moments (dim=3, level=8, order=8)", 8, 3) {}
bool run() const
{
GeneralMatrix m(3,3);
m.zeros();
m.get(0,0)=1; m.get(0,2)=0.5; m.get(1,1)=1;
m.get(1,0)=0.5;m.get(2,2)=2;m.get(2,1)=4;
return smolyak_normal_moments(m, 8, 8);
}
};
class ProductNormalMom1 : public TestRunnable {
public:
ProductNormalMom1()
: TestRunnable("Product normal moments (dim=2, level=4, order=4)", 4, 2) {}
bool run() const
{
GeneralMatrix m(2,2);
m.zeros(); m.get(0,0)=1; m.get(1,1)=1;
return product_normal_moments(m, 4, 4);
}
};
class ProductNormalMom2 : public TestRunnable {
public:
ProductNormalMom2()
: TestRunnable("Product normal moments (dim=3, level=8, order=8)", 8, 3) {}
bool run() const
{
GeneralMatrix m(3,3);
m.zeros();
m.get(0,0)=1; m.get(0,2)=0.5; m.get(1,1)=1;
m.get(1,0)=0.5;m.get(2,2)=2;m.get(2,1)=4;
return product_normal_moments(m, 8, 8);
}
};
class QMCNormalMom1 : public TestRunnable {
public:
QMCNormalMom1()
: TestRunnable("QMC normal moments (dim=2, level=1000, order=4)", 4, 2) {}
bool run() const
{
GeneralMatrix m(2,2);
m.zeros(); m.get(0,0)=1; m.get(1,1)=1;
return qmc_normal_moments(m, 4, 1000);
}
};
class QMCNormalMom2 : public TestRunnable {
public:
QMCNormalMom2()
: TestRunnable("QMC normal moments (dim=3, level=10000, order=8)", 8, 3) {}
bool run() const
{
GeneralMatrix m(3,3);
m.zeros();
m.get(0,0)=1; m.get(0,2)=0.5; m.get(1,1)=1;
m.get(1,0)=0.5;m.get(2,2)=2;m.get(2,1)=4;
return qmc_normal_moments(m, 8, 10000);
}
};
// note that here we pass 1,1 to tls since smolyak has its own PascalTriangle
class F1GaussLegendre : public TestRunnable {
public:
F1GaussLegendre()
: TestRunnable("Function1 Gauss-Legendre (dim=6, level=13", 1, 1) {}
bool run() const
{
Function1Trans f1(6);
Vector res(1); res[0] = 1.0;
return smolyak_product_cube(f1, res, 1e-2, 13);
}
};
class F1QuasiMCarlo : public TestRunnable {
public:
F1QuasiMCarlo()
: TestRunnable("Function1 Quasi-Monte Carlo (dim=6, level=1000000)", 1, 1) {}
bool run() const
{
Function1 f1(6);
return qmc_cube(f1, 1.0, 1.e-4, 1000000);
}
};
int main()
{
TestRunnable* all_tests[50];
// fill in vector of all tests
int num_tests = 0;
all_tests[num_tests++] = new SmolyakNormalMom1();
all_tests[num_tests++] = new SmolyakNormalMom2();
all_tests[num_tests++] = new ProductNormalMom1();
all_tests[num_tests++] = new ProductNormalMom2();
all_tests[num_tests++] = new QMCNormalMom1();
all_tests[num_tests++] = new QMCNormalMom2();
/*
all_tests[num_tests++] = new F1GaussLegendre();
all_tests[num_tests++] = new F1QuasiMCarlo();
*/
// find maximum dimension and maximum nvar
int dmax=0;
int nvmax = 0;
for (int i = 0; i < num_tests; i++) {
if (dmax < all_tests[i]->dim)
dmax = all_tests[i]->dim;
if (nvmax < all_tests[i]->nvar)
nvmax = all_tests[i]->nvar;
}
tls.init(dmax, nvmax); // initialize library
THREAD_GROUP::max_parallel_threads = num_threads;
// launch the tests
int success = 0;
for (int i = 0; i < num_tests; i++) {
try {
if (all_tests[i]->test())
success++;
} catch (const TLException& e) {
printf("Caugth TL exception in <%s>:\n", all_tests[i]->getName());
e.print();
} catch (SylvException& e) {
printf("Caught Sylv exception in <%s>:\n", all_tests[i]->getName());
e.printMessage();
}
}
printf("There were %d tests that failed out of %d tests run.\n",
num_tests - success, num_tests);
// destroy
for (int i = 0; i < num_tests; i++) {
delete all_tests[i];
}
return 0;
}

View File

@ -1,93 +1,42 @@
CWEBSRC = \
faa_di_bruno.cweb \
korder_stoch.cweb \
journal.cweb \
decision_rule.cweb \
dynamic_model.cweb \
random.cweb \
first_order.cweb \
normal_conjugate.cweb \
approximation.cweb \
global_check.cweb \
korder.cweb \
kord_exception.hweb \
random.hweb \
journal.hweb \
approximation.hweb \
korder_stoch.hweb \
dynamic_model.hweb \
decision_rule.hweb \
korder.hweb \
normal_conjugate.hweb \
first_order.hweb \
mersenne_twister.hweb \
global_check.hweb \
faa_di_bruno.hweb
GENERATED_FILES = \
faa_di_bruno.cpp \
korder_stoch.cpp \
journal.cpp \
decision_rule.cpp \
dynamic_model.cpp \
random.cpp \
first_order.cpp \
normal_conjugate.cpp \
approximation.cpp \
global_check.cpp \
korder.cpp \
kord_exception.h \
random.h \
journal.h \
approximation.h \
korder_stoch.h \
dynamic_model.h \
decision_rule.h \
korder.h \
normal_conjugate.h \
first_order.h \
mersenne_twister.h \
global_check.h \
faa_di_bruno.h
noinst_LIBRARIES = libkord.a
libkord_a_SOURCES = $(CWEBSRC) $(GENERATED_FILES)
libkord_a_CPPFLAGS = -I../sylv/cc -I../tl/cc -I../integ/cc -I$(top_srcdir)/mex/sources $(CPPFLAGS_MATIO)
libkord_a_CXXFLAGS = $(AM_CXXFLAGS) $(PTHREAD_CFLAGS)
libkord_a_SOURCES = \
approximation.cc \
approximation.hh \
decision_rule.cc \
decision_rule.hh \
dynamic_model.cc \
dynamic_model.hh \
faa_di_bruno.cc \
faa_di_bruno.hh \
first_order.cc \
first_order.hh \
global_check.cc \
global_check.hh \
kord_exception.hh \
korder.cc \
korder.hh \
korder_stoch.cc \
korder_stoch.hh \
journal.cc \
journal.hh \
normal_conjugate.cc \
normal_conjugate.hh \
seed_generator.cc \
seed_generator.hh
BUILT_SOURCES = $(GENERATED_FILES)
EXTRA_DIST = main.web dummy.ch
libkord_a_CPPFLAGS = -I../sylv/cc -I../tl/cc -I../integ/cc -I../utils/cc -I$(top_srcdir)/mex/sources $(CPPFLAGS_MATIO) -DDYNVERSION=\"$(PACKAGE_VERSION)\"
libkord_a_CXXFLAGS = $(AM_CXXFLAGS) $(THREAD_CXXFLAGS)
check_PROGRAMS = tests
tests_SOURCES = tests.cpp
tests_CPPFLAGS = -I../sylv/cc -I../tl/cc -I../integ/cc -I$(top_srcdir)/mex/sources
tests_CXXFLAGS = $(AM_CXXFLAGS) $(PTHREAD_CFLAGS)
tests_SOURCES = tests.cc
tests_CPPFLAGS = -I../sylv/cc -I../tl/cc -I../integ/cc -I../utils/cc -I$(top_srcdir)/mex/sources
tests_CXXFLAGS = $(AM_CXXFLAGS) $(THREAD_CXXFLAGS)
tests_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS_MATIO)
tests_LDADD = libkord.a ../tl/cc/libtl.a ../sylv/cc/libsylv.a $(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS) $(FLIBS) $(PTHREAD_LIBS) $(LIBADD_MATIO)
tests_LDADD = libkord.a ../tl/cc/libtl.a ../sylv/cc/libsylv.a ../utils/cc/libutils.a $(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS) $(FLIBS) $(LIBADD_MATIO)
check-local:
./tests
%.cpp: %.cweb dummy.ch
$(CTANGLE) -bhp $< dummy.ch $@
%.h: %.hweb dummy.ch
$(CTANGLE) -bhp $< dummy.ch $@
if HAVE_CWEAVE
if HAVE_PDFTEX
if HAVE_EPLAIN
pdf-local: kord.pdf
kord.pdf: main.web $(CWEBSRC)
$(CWEAVE) -bhp main.web
$(PDFTEX) main
mv main.pdf kord.pdf
endif
endif
endif
CLEANFILES = kord.pdf main.idx main.log main.scn main.tex main.toc out.txt
CLEANFILES = out.txt

View File

@ -0,0 +1,380 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
#include <utility>
#include "kord_exception.hh"
#include "approximation.hh"
#include "first_order.hh"
#include "korder_stoch.hh"
ZAuxContainer::ZAuxContainer(const _Ctype *gss, int ngss, int ng, int ny, int nu)
: StackContainer<FGSTensor>(4, 1)
{
stack_sizes = { ngss, ng, ny, nu };
conts[0] = gss;
calculateOffsets();
}
/* The getType() method corresponds to f(g**(y*,u,σ),0,0,0). For the first
argument we return matrix, for other three we return zero. */
ZAuxContainer::itype
ZAuxContainer::getType(int i, const Symmetry &s) const
{
if (i == 0)
if (s[2] > 0)
return itype::zero;
else
return itype::matrix;
return itype::zero;
}
Approximation::Approximation(DynamicModel &m, Journal &j, int ns, bool dr_centr, double qz_crit)
: model(m), journal(j),
ypart(model.nstat(), model.npred(), model.nboth(), model.nforw()),
mom(UNormalMoments(model.order(), model.getVcov())),
nvs{ypart.nys(), model.nexog(), model.nexog(), 1 },
steps(ns),
dr_centralize(dr_centr), qz_criterium(qz_crit), ss(ypart.ny(), steps+1)
{
ss.nans();
}
/* This just returns fdr with a check that it is created. */
const FoldDecisionRule &
Approximation::getFoldDecisionRule() const
{
KORD_RAISE_IF(!fdr,
"Folded decision rule has not been created in Approximation::getFoldDecisionRule");
return *fdr;
}
/* This just returns udr with a check that it is created. */
const UnfoldDecisionRule &
Approximation::getUnfoldDecisionRule() const
{
KORD_RAISE_IF(!udr,
"Unfolded decision rule has not been created in Approximation::getUnfoldDecisionRule");
return *udr;
}
/* This methods assumes that the deterministic steady state is
model.getSteady(). It makes an approximation about it and stores the
derivatives to rule_ders and rule_ders_ss. Also it runs a check() for
σ=0. */
void
Approximation::approxAtSteady()
{
model.calcDerivativesAtSteady();
FirstOrder fo(model.nstat(), model.npred(), model.nboth(), model.nforw(),
model.nexog(), model.getModelDerivatives().get(Symmetry{1}),
journal, qz_criterium);
KORD_RAISE_IF_X(!fo.isStable(),
"The model is not Blanchard-Kahn stable",
KORD_MD_NOT_STABLE);
if (model.order() >= 2)
{
KOrder korder(model.nstat(), model.npred(), model.nboth(), model.nforw(),
model.getModelDerivatives(), fo.getGy(), fo.getGu(),
model.getVcov(), journal);
korder.switchToFolded();
for (int k = 2; k <= model.order(); k++)
korder.performStep<Storage::fold>(k);
saveRuleDerivs(korder.getFoldDers());
}
else
{
FirstOrderDerivs<Storage::fold> fo_ders(fo);
saveRuleDerivs(fo_ders);
}
check(0.0);
}
/* This is the core routine of Approximation class.
First we solve for the approximation about the deterministic steady state.
Then we perform steps cycles toward the stochastic steady state. Each
cycle moves the size of shocks by dsigma=1.0/steps. At the end of a cycle,
we have rule_ders being the derivatives at stochastic steady state for
σ=sigma_so_far+dsigma and model.getSteady() being the steady state.
If the number of steps is zero, the decision rule dr at the bottom is
created from derivatives about deterministic steady state, with size of σ=1.
Otherwise, the dr is created from the approximation about stochastic
steady state with σ=0.
Within each cycle, we first make a backup of the last steady (from
initialization or from a previous cycle), then we calculate the fix point of
the last rule with σ=dsigma. This becomes a new steady state at the
σ=sigma_so_far+dsigma. We calculate expectations of g**(y,σ η,σ)
expressed as a Taylor expansion around the new σ and the new steady state.
Then we solve for the decision rule with explicit g** at t+1 and save the
rule.
After we reached σ=1, the decision rule is formed.
The biproduct of this method is the matrix ss, whose columns are steady
states for subsequent σs. The first column is the deterministic steady
state, the last column is the stochastic steady state for a full size of
shocks (σ=1). There are steps+1 columns. */
void
Approximation::walkStochSteady()
{
// initial approximation at deterministic steady
/* Here we solve for the deterministic steady state, calculate
approximation at the deterministic steady and save the steady state
to ss. */
model.solveDeterministicSteady();
approxAtSteady();
Vector steady0{ss.getCol(0)};
steady0 = model.getSteady();
double sigma_so_far = 0.0;
double dsigma = (steps == 0) ? 0.0 : 1.0/steps;
for (int i = 1; i <= steps; i++)
{
JournalRecordPair pa(journal);
pa << "Approximation about stochastic steady for sigma=" << sigma_so_far+dsigma << endrec;
Vector last_steady(model.getSteady());
// calculate fix-point of the last rule for dsigma
/* We form the DRFixPoint object from the last rule with σ=dsigma. Then
we save the steady state to ss. The new steady is also put to
model.getSteady(). */
DRFixPoint<Storage::fold> fp(*rule_ders, ypart, model.getSteady(), dsigma);
bool converged = fp.calcFixPoint(DecisionRule::emethod::horner, model.getSteady());
JournalRecord rec(journal);
rec << "Fix point calcs: iter=" << fp.getNumIter() << ", newton_iter="
<< fp.getNewtonTotalIter() << ", last_newton_iter=" << fp.getNewtonLastIter() << ".";
if (converged)
rec << " Converged." << endrec;
else
{
rec << " Not converged!!" << endrec;
KORD_RAISE_X("Fix point calculation not converged", KORD_FP_NOT_CONV);
}
Vector steadyi{ss.getCol(i)};
steadyi = model.getSteady();
// calculate hh as expectations of the last g**
/* We form the steady state shift dy, which is the new steady state
minus the old steady state. Then we create StochForwardDerivs object,
which calculates the derivatives of g** expectations at new sigma and
new steady. */
Vector dy(model.getSteady());
dy.add(-1.0, last_steady);
StochForwardDerivs<Storage::fold> hh(ypart, model.nexog(), *rule_ders_ss, mom, dy,
dsigma, sigma_so_far);
JournalRecord rec1(journal);
rec1 << "Calculation of g** expectations done" << endrec;
// form KOrderStoch, solve and save
/* We calculate derivatives of the model at the new steady, form
KOrderStoch object and solve, and save the rule. */
model.calcDerivativesAtSteady();
KOrderStoch korder_stoch(ypart, model.nexog(), model.getModelDerivatives(),
hh, journal);
for (int d = 1; d <= model.order(); d++)
korder_stoch.performStep<Storage::fold>(d);
saveRuleDerivs(korder_stoch.getFoldDers());
check(sigma_so_far+dsigma);
sigma_so_far += dsigma;
}
// construct the resulting decision rules
udr.reset();
fdr = std::make_unique<FoldDecisionRule>(*rule_ders, ypart, model.nexog(),
model.getSteady(), 1.0-sigma_so_far);
if (steps == 0 && dr_centralize)
{
// centralize decision rule for zero steps
DRFixPoint<Storage::fold> fp(*rule_ders, ypart, model.getSteady(), 1.0);
bool converged = fp.calcFixPoint(DecisionRule::emethod::horner, model.getSteady());
JournalRecord rec(journal);
rec << "Fix point calcs: iter=" << fp.getNumIter() << ", newton_iter="
<< fp.getNewtonTotalIter() << ", last_newton_iter=" << fp.getNewtonLastIter() << ".";
if (converged)
rec << " Converged." << endrec;
else
{
rec << " Not converged!!" << endrec;
KORD_RAISE_X("Fix point calculation not converged", KORD_FP_NOT_CONV);
}
{
JournalRecordPair recp(journal);
recp << "Centralizing about fix-point." << endrec;
fdr = std::make_unique<FoldDecisionRule>(*fdr, model.getSteady());
}
}
}
/* Here we simply make a new hardcopy of the given rule rule_ders,
and make a new container of in-place subtensors of the derivatives
corresponding to forward looking variables. The given container comes
from a temporary object and will be destroyed. */
void
Approximation::saveRuleDerivs(const FGSContainer &g)
{
rule_ders = std::make_unique<FGSContainer>(g);
rule_ders_ss = std::make_unique<FGSContainer>(4);
for (auto &run : *rule_ders)
{
auto ten = std::make_unique<FGSTensor>(ypart.nstat+ypart.npred, ypart.nyss(), *(run.second));
rule_ders_ss->insert(std::move(ten));
}
}
/* This method calculates a shift of the system equations due to integrating
shocks at a given σ and current steady state. More precisely, if
F(y,u,u,σ)=f(g**(g*(y,u,σ),u,σ),g(y,u,σ),y,u)
then the method returns a vector
σ
[F_u]_αα_d Σ^αα_d
d=1 d!
For a calculation of [F_u] we use ZAuxContainer, so we create its object.
In each cycle we calculate [F_u], and then multiply with the shocks, and
add the σ/d! multiple to the result. */
void
Approximation::calcStochShift(Vector &out, double at_sigma) const
{
KORD_RAISE_IF(out.length() != ypart.ny(),
"Wrong length of output vector for Approximation::calcStochShift");
out.zeros();
ZAuxContainer zaux(rule_ders_ss.get(), ypart.nyss(), ypart.ny(),
ypart.nys(), model.nexog());
int dfac = 1;
for (int d = 1; d <= rule_ders->getMaxDim(); d++, dfac *= d)
{
if (KOrder::is_even(d))
{
Symmetry sym{0, d, 0, 0};
// calculate F_uᵈ via ZAuxContainer
auto ten = std::make_unique<FGSTensor>(ypart.ny(), TensorDimens(sym, nvs));
ten->zeros();
for (int l = 1; l <= d; l++)
{
const FSSparseTensor &f = model.getModelDerivatives().get(Symmetry{l});
zaux.multAndAdd(f, *ten);
}
// multiply with shocks and add to result
auto tmp = std::make_unique<FGSTensor>(ypart.ny(), TensorDimens(Symmetry{0, 0, 0, 0}, nvs));
tmp->zeros();
ten->contractAndAdd(1, *tmp, mom.get(Symmetry{d}));
out.add(pow(at_sigma, d)/dfac, tmp->getData());
}
}
}
/* This method calculates and reports
σ
f(ȳ) + [F_u]_αα_d Σ^αα_d
d=1 d!
at ȳ, zero shocks and σ. This number should be zero.
We evaluate the error both at a given σ and σ=1.0. */
void
Approximation::check(double at_sigma) const
{
Vector stoch_shift(ypart.ny());
Vector system_resid(ypart.ny());
Vector xx(model.nexog());
xx.zeros();
model.evaluateSystem(system_resid, model.getSteady(), xx);
calcStochShift(stoch_shift, at_sigma);
stoch_shift.add(1.0, system_resid);
JournalRecord rec1(journal);
rec1 << "Error of current approximation for shocks at sigma " << at_sigma
<< " is " << stoch_shift.getMax() << endrec;
calcStochShift(stoch_shift, 1.0);
stoch_shift.add(1.0, system_resid);
JournalRecord rec2(journal);
rec2 << "Error of current approximation for full shocks is " << stoch_shift.getMax() << endrec;
}
/* The method returns unconditional variance of endogenous variables
based on the first order. The first order approximation looks like
ŷ = g_y* ŷ* + g u
where ŷ denotes a deviation from the steady state. It can be written as
ŷ = (0 g_y* 0) ŷ + g u
which yields unconditional covariance V for which
V = GVG + g Σ g
where G=(0 g_y* 0) and Σ is the covariance of the shocks.
For solving this Lyapunov equation we use the Sylvester module, which
solves equation of the type
AX + BX(CC) = D
So we invoke the Sylvester solver for the first dimension with A = I,
B = G, C = G and D = g Σ g. */
TwoDMatrix
Approximation::calcYCov() const
{
const TwoDMatrix &gy = rule_ders->get(Symmetry{1, 0, 0, 0});
const TwoDMatrix &gu = rule_ders->get(Symmetry{0, 1, 0, 0});
TwoDMatrix G(model.numeq(), model.numeq());
G.zeros();
G.place(gy, 0, model.nstat());
TwoDMatrix B(const_cast<const TwoDMatrix &>(G));
B.mult(-1.0);
TwoDMatrix C(transpose(G));
TwoDMatrix A(model.numeq(), model.numeq());
A.zeros();
for (int i = 0; i < model.numeq(); i++)
A.get(i, i) = 1.0;
TwoDMatrix X((gu * model.getVcov()) * transpose(gu));
GeneralSylvester gs(1, model.numeq(), model.numeq(), 0,
A.getData(), B.getData(), C.getData(), X.getData());
gs.solve();
return X;
}

View File

@ -1,421 +0,0 @@
@q $Id: approximation.cweb 2344 2009-02-09 20:36:08Z michel $ @>
@q Copyright 2005, Ondra Kamenik @>
@ Start of {\tt approximation.cpp} file.
@c
#include "kord_exception.h"
#include "approximation.h"
#include "first_order.h"
#include "korder_stoch.h"
@<|ZAuxContainer| constructor code@>;
@<|ZAuxContainer::getType| code@>;
@<|Approximation| constructor code@>;
@<|Approximation| destructor code@>;
@<|Approximation::getFoldDecisionRule| code@>;
@<|Approximation::getUnfoldDecisionRule| code@>;
@<|Approximation::approxAtSteady| code@>;
@<|Approximation::walkStochSteady| code@>;
@<|Approximation::saveRuleDerivs| code@>;
@<|Approximation::calcStochShift| code@>;
@<|Approximation::check| code@>;
@<|Approximation::calcYCov| code@>;
@
@<|ZAuxContainer| constructor code@>=
ZAuxContainer::ZAuxContainer(const _Ctype* gss, int ngss, int ng, int ny, int nu)
: StackContainer<FGSTensor>(4,1)
{
stack_sizes[0] = ngss; stack_sizes[1] = ng;
stack_sizes[2] = ny; stack_sizes[3] = nu;
conts[0] = gss;
calculateOffsets();
}
@ The |getType| method corresponds to
$f(g^{**}(y^*,u',\sigma),0,0,0)$. For the first argument we return
|matrix|, for other three we return |zero|.
@<|ZAuxContainer::getType| code@>=
ZAuxContainer::itype ZAuxContainer::getType(int i, const Symmetry& s) const
{
if (i == 0)
if (s[2] > 0)
return zero;
else
return matrix;
return zero;
}
@
@<|Approximation| constructor code@>=
Approximation::Approximation(DynamicModel& m, Journal& j, int ns, bool dr_centr, double qz_crit)
: model(m), journal(j), rule_ders(NULL), rule_ders_ss(NULL), fdr(NULL), udr(NULL),
ypart(model.nstat(), model.npred(), model.nboth(), model.nforw()),
mom(UNormalMoments(model.order(), model.getVcov())), nvs(4), steps(ns),
dr_centralize(dr_centr), qz_criterium(qz_crit), ss(ypart.ny(), steps+1)
{
nvs[0] = ypart.nys(); nvs[1] = model.nexog();
nvs[2] = model.nexog(); nvs[3] = 1;
ss.nans();
}
@
@<|Approximation| destructor code@>=
Approximation::~Approximation()
{
if (rule_ders_ss) delete rule_ders_ss;
if (rule_ders) delete rule_ders;
if (fdr) delete fdr;
if (udr) delete udr;
}
@ This just returns |fdr| with a check that it is created.
@<|Approximation::getFoldDecisionRule| code@>=
const FoldDecisionRule& Approximation::getFoldDecisionRule() const
{
KORD_RAISE_IF(fdr == NULL,
"Folded decision rule has not been created in Approximation::getFoldDecisionRule");
return *fdr;
}
@ This just returns |udr| with a check that it is created.
@<|Approximation::getUnfoldDecisionRule| code@>=
const UnfoldDecisionRule& Approximation::getUnfoldDecisionRule() const
{
KORD_RAISE_IF(udr == NULL,
"Unfolded decision rule has not been created in Approximation::getUnfoldDecisionRule");
return *udr;
}
@ This methods assumes that the deterministic steady state is
|model.getSteady()|. It makes an approximation about it and stores the
derivatives to |rule_ders| and |rule_ders_ss|. Also it runs a |check|
for $\sigma=0$.
@<|Approximation::approxAtSteady| code@>=
void Approximation::approxAtSteady()
{
model.calcDerivativesAtSteady();
FirstOrder fo(model.nstat(), model.npred(), model.nboth(), model.nforw(),
model.nexog(), *(model.getModelDerivatives().get(Symmetry(1))),
journal, qz_criterium);
KORD_RAISE_IF_X(! fo.isStable(),
"The model is not Blanchard-Kahn stable",
KORD_MD_NOT_STABLE);
if (model.order() >= 2) {
KOrder korder(model.nstat(), model.npred(), model.nboth(), model.nforw(),
model.getModelDerivatives(), fo.getGy(), fo.getGu(),
model.getVcov(), journal);
korder.switchToFolded();
for (int k = 2; k <= model.order(); k++)
korder.performStep<KOrder::fold>(k);
saveRuleDerivs(korder.getFoldDers());
} else {
FirstOrderDerivs<KOrder::fold> fo_ders(fo);
saveRuleDerivs(fo_ders);
}
check(0.0);
}
@ This is the core routine of |Approximation| class.
First we solve for the approximation about the deterministic steady
state. Then we perform |steps| cycles toward the stochastic steady
state. Each cycle moves the size of shocks by |dsigma=1.0/steps|. At
the end of a cycle, we have |rule_ders| being the derivatives at
stochastic steady state for $\sigma=sigma\_so\_far+dsigma$ and
|model.getSteady()| being the steady state.
If the number of |steps| is zero, the decision rule |dr| at the bottom
is created from derivatives about deterministic steady state, with
size of $\sigma=1$. Otherwise, the |dr| is created from the
approximation about stochastic steady state with $\sigma=0$.
Within each cycle, we first make a backup of the last steady (from
initialization or from a previous cycle), then we calculate the fix
point of the last rule with $\sigma=dsigma$. This becomes a new steady
state at the $\sigma=sigma\_so\_far+dsigma$. We calculate expectations
of $g^{**}(y,\sigma\eta_{t+1},\sigma$ expressed as a Taylor expansion
around the new $\sigma$ and the new steady state. Then we solve for
the decision rule with explicit $g^{**}$ at $t+1$ and save the rule.
After we reached $\sigma=1$, the decision rule is formed.
The biproduct of this method is the matrix |ss|, whose columns are
steady states for subsequent $\sigma$s. The first column is the
deterministic steady state, the last column is the stochastic steady
state for a full size of shocks ($\sigma=1$). There are |steps+1|
columns.
@<|Approximation::walkStochSteady| code@>=
void Approximation::walkStochSteady()
{
@<initial approximation at deterministic steady@>;
double sigma_so_far = 0.0;
double dsigma = (steps == 0)? 0.0 : 1.0/steps;
for (int i = 1; i <= steps; i++) {
JournalRecordPair pa(journal);
pa << "Approximation about stochastic steady for sigma=" << sigma_so_far+dsigma << endrec;
Vector last_steady((const Vector&)model.getSteady());
@<calculate fix-point of the last rule for |dsigma|@>;
@<calculate |hh| as expectations of the last $g^{**}$@>;
@<form |KOrderStoch|, solve and save@>;
check(sigma_so_far+dsigma);
sigma_so_far += dsigma;
}
@<construct the resulting decision rules@>;
}
@ Here we solve for the deterministic steady state, calculate
approximation at the deterministic steady and save the steady state
to |ss|.
@<initial approximation at deterministic steady@>=
model.solveDeterministicSteady();
approxAtSteady();
Vector steady0(ss, 0);
steady0 = (const Vector&)model.getSteady();
@ We form the |DRFixPoint| object from the last rule with
$\sigma=dsigma$. Then we save the steady state to |ss|. The new steady
is also put to |model.getSteady()|.
@<calculate fix-point of the last rule for |dsigma|@>=
DRFixPoint<KOrder::fold> fp(*rule_ders, ypart, model.getSteady(), dsigma);
bool converged = fp.calcFixPoint(DecisionRule::horner, model.getSteady());
JournalRecord rec(journal);
rec << "Fix point calcs: iter=" << fp.getNumIter() << ", newton_iter="
<< fp.getNewtonTotalIter() << ", last_newton_iter=" << fp.getNewtonLastIter() << ".";
if (converged)
rec << " Converged." << endrec;
else {
rec << " Not converged!!" << endrec;
KORD_RAISE_X("Fix point calculation not converged", KORD_FP_NOT_CONV);
}
Vector steadyi(ss, i);
steadyi = (const Vector&)model.getSteady();
@ We form the steady state shift |dy|, which is the new steady state
minus the old steady state. Then we create |StochForwardDerivs|
object, which calculates the derivatives of $g^{**}$ expectations at
new sigma and new steady.
@<calculate |hh| as expectations of the last $g^{**}$@>=
Vector dy((const Vector&)model.getSteady());
dy.add(-1.0, last_steady);
StochForwardDerivs<KOrder::fold> hh(ypart, model.nexog(), *rule_ders_ss, mom, dy,
dsigma, sigma_so_far);
JournalRecord rec1(journal);
rec1 << "Calculation of g** expectations done" << endrec;
@ We calculate derivatives of the model at the new steady, form
|KOrderStoch| object and solve, and save the rule.
@<form |KOrderStoch|, solve and save@>=
model.calcDerivativesAtSteady();
KOrderStoch korder_stoch(ypart, model.nexog(), model.getModelDerivatives(),
hh, journal);
for (int d = 1; d <= model.order(); d++) {
korder_stoch.performStep<KOrder::fold>(d);
}
saveRuleDerivs(korder_stoch.getFoldDers());
@
@<construct the resulting decision rules@>=
if (fdr) {
delete fdr;
fdr = NULL;
}
if (udr) {
delete udr;
udr = NULL;
}
fdr = new FoldDecisionRule(*rule_ders, ypart, model.nexog(),
model.getSteady(), 1.0-sigma_so_far);
if (steps == 0 && dr_centralize) {
@<centralize decision rule for zero steps@>;
}
@
@<centralize decision rule for zero steps@>=
DRFixPoint<KOrder::fold> fp(*rule_ders, ypart, model.getSteady(), 1.0);
bool converged = fp.calcFixPoint(DecisionRule::horner, model.getSteady());
JournalRecord rec(journal);
rec << "Fix point calcs: iter=" << fp.getNumIter() << ", newton_iter="
<< fp.getNewtonTotalIter() << ", last_newton_iter=" << fp.getNewtonLastIter() << ".";
if (converged)
rec << " Converged." << endrec;
else {
rec << " Not converged!!" << endrec;
KORD_RAISE_X("Fix point calculation not converged", KORD_FP_NOT_CONV);
}
{
JournalRecordPair recp(journal);
recp << "Centralizing about fix-point." << endrec;
FoldDecisionRule* dr_backup = fdr;
fdr = new FoldDecisionRule(*dr_backup, model.getSteady());
delete dr_backup;
}
@ Here we simply make a new hardcopy of the given rule |rule_ders|,
and make a new container of in-place subtensors of the derivatives
corresponding to forward looking variables. The given container comes
from a temporary object and will be destroyed.
@<|Approximation::saveRuleDerivs| code@>=
void Approximation::saveRuleDerivs(const FGSContainer& g)
{
if (rule_ders) {
delete rule_ders;
delete rule_ders_ss;
}
rule_ders = new FGSContainer(g);
rule_ders_ss = new FGSContainer(4);
for (FGSContainer::iterator run = (*rule_ders).begin(); run != (*rule_ders).end(); ++run) {
FGSTensor* ten = new FGSTensor(ypart.nstat+ypart.npred, ypart.nyss(), *((*run).second));
rule_ders_ss->insert(ten);
}
}
@ This method calculates a shift of the system equations due to
integrating shocks at a given $\sigma$ and current steady state. More precisely, if
$$F(y,u,u',\sigma)=f(g^{**}(g^*(y,u,\sigma),u',\sigma),g(y,u,\sigma),y,u)$$
then the method returns a vector
$$\sum_{d=1}{1\over d!}\sigma^d\left[F_{u'^d}\right]_{\alpha_1\ldots\alpha_d}
\Sigma^{\alpha_1\ldots\alpha_d}$$
For a calculation of $\left[F_{u'^d}\right]$ we use |@<|ZAuxContainer|
class declaration@>|, so we create its object. In each cycle we
calculate $\left[F_{u'^d}\right]$@q'@>, and then multiply with the shocks,
and add the ${\sigma^d\over d!}$ multiple to the result.
@<|Approximation::calcStochShift| code@>=
void Approximation::calcStochShift(Vector& out, double at_sigma) const
{
KORD_RAISE_IF(out.length() != ypart.ny(),
"Wrong length of output vector for Approximation::calcStochShift");
out.zeros();
ZAuxContainer zaux(rule_ders_ss, ypart.nyss(), ypart.ny(),
ypart.nys(), model.nexog());
int dfac = 1;
for (int d = 1; d <= rule_ders->getMaxDim(); d++, dfac*=d) {
if ( KOrder::is_even(d)) {
Symmetry sym(0,d,0,0);
@<calculate $F_{u'^d}$ via |ZAuxContainer|@>;@q'@>
@<multiply with shocks and add to result@>;
}
}
}
@
@<calculate $F_{u'^d}$ via |ZAuxContainer|@>=
FGSTensor* ten = new FGSTensor(ypart.ny(), TensorDimens(sym, nvs));
ten->zeros();
for (int l = 1; l <= d; l++) {
const FSSparseTensor* f = model.getModelDerivatives().get(Symmetry(l));
zaux.multAndAdd(*f, *ten);
}
@
@<multiply with shocks and add to result@>=
FGSTensor* tmp = new FGSTensor(ypart.ny(), TensorDimens(Symmetry(0,0,0,0), nvs));
tmp->zeros();
ten->contractAndAdd(1, *tmp, *(mom.get(Symmetry(d))));
out.add(pow(at_sigma,d)/dfac, tmp->getData());
delete ten;
delete tmp;
@ This method calculates and reports
$$f(\bar y)+\sum_{d=1}{1\over d!}\sigma^d\left[F_{u'^d}\right]_{\alpha_1\ldots\alpha_d}
\Sigma^{\alpha_1\ldots\alpha_d}$$
at $\bar y$, zero shocks and $\sigma$. This number should be zero.
We evaluate the error both at a given $\sigma$ and $\sigma=1.0$.
@<|Approximation::check| code@>=
void Approximation::check(double at_sigma) const
{
Vector stoch_shift(ypart.ny());
Vector system_resid(ypart.ny());
Vector xx(model.nexog());
xx.zeros();
model.evaluateSystem(system_resid, model.getSteady(), xx);
calcStochShift(stoch_shift, at_sigma);
stoch_shift.add(1.0, system_resid);
JournalRecord rec1(journal);
rec1 << "Error of current approximation for shocks at sigma " << at_sigma
<< " is " << stoch_shift.getMax() << endrec;
calcStochShift(stoch_shift, 1.0);
stoch_shift.add(1.0, system_resid);
JournalRecord rec2(journal);
rec2 << "Error of current approximation for full shocks is " << stoch_shift.getMax() << endrec;
}
@ The method returns unconditional variance of endogenous variables
based on the first order. The first order approximation looks like
$$\hat y_t=g_{y^*}\hat y^*_{t-1}+g_uu_t$$
where $\hat y$ denotes a deviation from the steady state. It can be written as
$$\hat y_t=\left[0\, g_{y^*}\, 0\right]\hat y_{t-1}+g_uu_t$$
which yields unconditional covariance $V$ for which
$$V=GVG^T + g_u\Sigma g_u^T,$$
where $G=[0\, g_{y^*}\, 0]$ and $\Sigma$ is the covariance of the shocks.
For solving this Lyapunov equation we use the Sylvester module, which
solves equation of the type
$$AX+BX(C\otimes\cdots\otimes C)=D$$
So we invoke the Sylvester solver for the first dimension with $A=I$,
$B=-G$, $C=G^T$ and $D=g_u\Sigma g_u^T$.
@<|Approximation::calcYCov| code@>=
TwoDMatrix* Approximation::calcYCov() const
{
const TwoDMatrix& gy = *(rule_ders->get(Symmetry(1,0,0,0)));
const TwoDMatrix& gu = *(rule_ders->get(Symmetry(0,1,0,0)));
TwoDMatrix G(model.numeq(), model.numeq());
G.zeros();
G.place(gy, 0, model.nstat());
TwoDMatrix B((const TwoDMatrix&)G);
B.mult(-1.0);
TwoDMatrix C(G, "transpose");
TwoDMatrix A(model.numeq(), model.numeq());
A.zeros();
for (int i = 0; i < model.numeq(); i++)
A.get( i,i) = 1.0;
TwoDMatrix guSigma(gu, model.getVcov());
TwoDMatrix guTrans(gu, "transpose");
TwoDMatrix* X = new TwoDMatrix(guSigma, guTrans);
GeneralSylvester gs(1, model.numeq(), model.numeq(), 0,
A.base(), B.base(), C.base(), X->base());
gs.solve();
return X;
}
@ End of {\tt approximation.cpp} file.

View File

@ -0,0 +1,170 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
// Approximating model solution
/* The class Approximation in this file is a main interface to the
algorithms calculating approximations to the decision rule about
deterministic and stochastic steady states.
The approximation about a deterministic steady state is solved by classes
FirstOrder and KOrder. The approximation around the stochastic steady state
is computed by class KOrderStoch together with a method of Approximation
class.
The approximation around the stochastic steady state is done with an
explicit expression of forward derivatives of g**. More formally,
we have to solve the decision rule g from the implicit system:
𝔼(f(g**(g*(y*,u,σ),u,σ),g(y*,u,σ),y,u)) = 0
The term within the expectations can be Taylor expanded, and the expectation
can be driven into the formula. However, when doing this at σ0, the term
g** at σ0 is dependent on u and thus the integral of its approximation
includes all derivatives w.r.t. u of g**. Note that for σ=0, the derivatives
of g** in this context are constant. This is the main difference between the
approximation at deterministic steady (σ=0), and stochastic steady (σ0).
This means that the k-order derivative of the above equation at σ0 depends
on all derivatives of g** (including those with order greater than k).
The explicit expression of the forward g** means that the derivatives of g
are not solved simultaneously, but that the forward derivatives of g** are
calculated as an extrapolation based on the approximation at lower σ. This
is exactly what does Approximation::walkStochSteady(). It starts at the
deterministic steady state, and in a few steps it adds to σ explicitly
expressing forward g** from a previous step.
Further details on the both solution methods are given in (todo: put
references here when they exist).
Very important note: all classes here used for calculation of decision
rule approximation are folded. For the time being, it seems that Faà
Di Bruno formula is quicker for folded tensors, and that is why we
stick to folded tensors here. However, when the calcs are done, we
calculate also its unfolded versions, to be available for simulations
and so on. */
#ifndef APPROXIMATION_H
#define APPROXIMATION_H
#include "dynamic_model.hh"
#include "decision_rule.hh"
#include "korder.hh"
#include "journal.hh"
#include <memory>
/* This class is used to calculate derivatives by Faà Di Bruno of
f(g**(g*(y*,u,σ),u,σ),g(y*,u,σ),y*,u) with respect to u. In order to keep
it as simple as possible, the class represents an equivalent (with respect
to u) container for f(g**(y*,u,σ),0,0,0). The class is used only for
evaluation of approximation error in Approximation class, which is
calculated in Approximation::calcStochShift().
Since it is a folded version, we inherit from StackContainer<FGSTensor> and
FoldedStackContainer. To construct it, we need only the g** container and
size of stacks. */
class ZAuxContainer : public StackContainer<FGSTensor>, public FoldedStackContainer
{
public:
using _Ctype = StackContainer<FGSTensor>::_Ctype;
using itype = StackContainer<FGSTensor>::itype;
ZAuxContainer(const _Ctype *gss, int ngss, int ng, int ny, int nu);
itype getType(int i, const Symmetry &s) const override;
};
/* This class provides an interface to approximation algorithms. The core
method is walkStochSteady() which calculates the approximation about
stochastic steady state in a given number of steps. The number is given as a
parameter ns of the constructor. If the number is equal to zero, the
resulted approximation is about the deterministic steady state.
An object is constructed from the DynamicModel, and the number of steps
ns. Also, we pass a reference to journal. That's all. The result of the
core method walkStochSteady() is a decision rule dr and a matrix ss
whose columns are steady states for increasing σ during the walk. Both can
be retrived by public methods. The first column of the matrix is the
deterministic steady state, the last is the stochastic steady state for the
full size shocks.
The method walkStochSteady() calls the following methods: approxAtSteady()
calculates an initial approximation about the deterministic steady,
saveRuleDerivs() saves derivatives of a rule for the following step in
rule_ders and rule_ders_ss (see Approximation::saveRuleDerivs() for
their description), check() reports an error of the current approximation
and calcStochShift() (called from check()) calculates a shift of the system
equations due to uncertainity.
dr_centralize is a new option. Dynare++ was automatically expressing
results around the fixed point instead of the deterministic steady state.
dr_centralize controls this behavior. */
class Approximation
{
DynamicModel &model;
Journal &journal;
std::unique_ptr<FGSContainer> rule_ders;
std::unique_ptr<FGSContainer> rule_ders_ss;
std::unique_ptr<FoldDecisionRule> fdr;
std::unique_ptr<UnfoldDecisionRule> udr;
const PartitionY ypart;
const FNormalMoments mom;
IntSequence nvs;
int steps;
bool dr_centralize;
double qz_criterium;
TwoDMatrix ss;
public:
Approximation(DynamicModel &m, Journal &j, int ns, bool dr_centr, double qz_crit);
const FoldDecisionRule &getFoldDecisionRule() const;
const UnfoldDecisionRule &getUnfoldDecisionRule() const;
const TwoDMatrix &
getSS() const
{
return ss;
}
const DynamicModel &
getModel() const
{
return model;
}
void walkStochSteady();
TwoDMatrix calcYCov() const;
const FGSContainer &
get_rule_ders() const
{
return *rule_ders;
}
const FGSContainer &
get_rule_ders_ss() const
{
return *rule_ders_ss;
}
protected:
void approxAtSteady();
void calcStochShift(Vector &out, double at_sigma) const;
void saveRuleDerivs(const FGSContainer &g);
void check(double at_sigma) const;
};
#endif

View File

@ -1,161 +0,0 @@
@q $Id: approximation.hweb 2352 2009-09-03 19:18:15Z michel $ @>
@q Copyright 2005, Ondra Kamenik @>
@*2 Approximating model solution. Start of {\tt approximation.h} file.
The class |Approximation| in this file is a main interface to the
algorithms calculating approximations to the decision rule about
deterministic and stochastic steady states.
The approximation about a deterministic steady state is solved by
classes |@<|FirstOrder| class declaration@>| and |@<|KOrder| class
declaration@>|. The approximation about the stochastic steady state is
solved by class |@<|KOrderStoch| class declaration@>| together with a
method of |Approximation| class |@<|Approximation::walkStochSteady|
code@>|.
The approximation about the stochastic steady state is done with
explicit expression of forward derivatives of $g^{**}$. More formally,
we have to solve the decision rule $g$ from the implicit system:
$$E_t(f(g^{**}(g^*(y^*,u_t,\sigma),u_{t+1},\sigma),g(y^*,u_t,\sigma),y_t,u_t))=0$$
The term within the expectations can be Taylor expanded, and the
expectation can be driven into the formula. However, when doing this
at $\sigma\not=0$, the term $g^{**}$ at $\sigma\not=0$ is dependent on
$u_{t+1}$ and thus the integral of its approximation includes all
derivatives wrt. $u$ of $g^{**}$. Note that for $\sigma=0$, the
derivatives of $g^{**}$ in this context are constant. This is the main
difference between the approximation at deterministic steady
($\sigma=0$), and stochastic steady ($\sigma\not=0$). This means that
$k$-order derivative of the above equation at $\sigma\not=0$ depends of
all derivatives of $g^**$ (including those with order greater than
$k$).
The explicit expression of the forward $g^{**}$ means that the
derivatives of $g$ are not solved simultaneously, but that the forward
derivatives of $g^{**}$ are calculated as an extrapolation based on
the approximation at lower $\sigma$. This is exactly what does the
|@<|Approximation::walkStochSteady| code@>|. It starts at the
deterministic steady state, and in a few steps it adds to $\sigma$
explicitly expressing forward $g^{**}$ from a previous step.
Further details on the both solution methods are given in (todo: put
references here when they exist).
Very important note: all classes here used for calculation of decision
rule approximation are folded. For the time being, it seems that faa
Di Bruno formula is quicker for folded tensors, and that is why we
stick to folded tensors here. However, when the calcs are done, we
calculate also its unfolded versions, to be available for simulations
and so on.
@s ZAuxContainer int
@s Approximation int
@c
#ifndef APPROXIMATION_H
#define APPROXIMATION_H
#include "dynamic_model.h"
#include "decision_rule.h"
#include "korder.h"
#include "journal.h"
@<|ZAuxContainer| class declaration@>;
@<|Approximation| class declaration@>;
#endif
@ This class is used to calculate derivatives by faa Di Bruno of the
$$f(g^{**}(g^*(y^*,u,\sigma),u',\sigma),g(y^*,u,\sigma),y^*,u)$$ with
respect $u'$. In order to keep it as simple as possible, the class
represents an equivalent (with respect to $u'$) container for
$f(g^{**}(y^*,u',\sigma),0,0,0)$. The class is used only for
evaluation of approximation error in |Approximation| class, which is
calculated in |Approximation::calcStochShift| method.
Since it is a folded version, we inherit from
|StackContainer<FGSTensor>| and |FoldedStackContainer|. To construct
it, we need only the $g^{**}$ container and size of stacks.
@<|ZAuxContainer| class declaration@>=
class ZAuxContainer : public StackContainer<FGSTensor>, public FoldedStackContainer {
public:@;
typedef StackContainer<FGSTensor>::_Ctype _Ctype;
typedef StackContainer<FGSTensor>::itype itype;
ZAuxContainer(const _Ctype* gss, int ngss, int ng, int ny, int nu);
itype getType(int i, const Symmetry& s) const;
};
@ This class provides an interface to approximation algorithms. The
core method is |walkStochSteady| which calculates the approximation
about stochastic steady state in a given number of steps. The number
is given as a parameter |ns| of the constructor. If the number is
equal to zero, the resulted approximation is about the deterministic
steady state.
An object is constructed from the |DynamicModel|, and the number of
steps |ns|. Also, we pass a reference to journal. That's all. The
result of the core method |walkStochSteady| is a decision rule |dr|
and a matrix |ss| whose columns are steady states for increasing
$\sigma$ during the walk. Both can be retrived by public methods. The
first column of the matrix is the deterministic steady state, the last
is the stochastic steady state for the full size shocks.
The method |walkStochSteady| calls the following methods:
|approxAtSteady| calculates an initial approximation about the
deterministic steady, |saveRuleDerivs| saves derivatives of a rule for
the following step in |rule_ders| and |rule_ders_ss| (see
|@<|Approximation::saveRuleDerivs| code@>| for their description),
|check| reports an error of the current approximation and
|calcStochShift| (called from |check|) calculates a shift of the
system equations due to uncertainity.
dr\_centralize is a new option. dynare++ was automatically expressing
results around the fixed point instead of the deterministic steady
state. dr\_centralize controls this behavior.
@<|Approximation| class declaration@>=
class Approximation {
DynamicModel& model;
Journal& journal;
FGSContainer* rule_ders;
FGSContainer* rule_ders_ss;
FoldDecisionRule* fdr;
UnfoldDecisionRule* udr;
const PartitionY ypart;
const FNormalMoments mom;
IntSequence nvs;
int steps;
bool dr_centralize;
double qz_criterium;
TwoDMatrix ss;
public:@;
Approximation(DynamicModel& m, Journal& j, int ns, bool dr_centr, double qz_crit);
virtual ~Approximation();
const FoldDecisionRule& getFoldDecisionRule() const;
const UnfoldDecisionRule& getUnfoldDecisionRule() const;
const TwoDMatrix& getSS() const
{@+ return ss;@+}
const DynamicModel& getModel() const
{@+ return model;@+}
void walkStochSteady();
TwoDMatrix* calcYCov() const;
const FGSContainer* get_rule_ders() const
{@+ return rule_ders;@+}
const FGSContainer* get_rule_ders_ss() const
{@+ return rule_ders;@+}
protected:@;
void approxAtSteady();
void calcStochShift(Vector& out, double at_sigma) const;
void saveRuleDerivs(const FGSContainer& g);
void check(double at_sigma) const;
};
@ End of {\tt approximation.h} file.

View File

@ -0,0 +1,586 @@
/*
* Copyright © 2004 Ondra Kamenik
* 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/>.
*/
#include "kord_exception.hh"
#include "decision_rule.hh"
#include "dynamic_model.hh"
#include "seed_generator.hh"
#include "SymSchurDecomp.hh"
#include <dynlapack.h>
#include <limits>
#include <utility>
#include <memory>
// FoldDecisionRule conversion from UnfoldDecisionRule
FoldDecisionRule::FoldDecisionRule(const UnfoldDecisionRule &udr)
: DecisionRuleImpl<Storage::fold>(ctraits<Storage::fold>::Tpol(udr.nrows(), udr.nvars()),
udr.ypart, udr.nu, udr.ysteady)
{
for (const auto &it : udr)
insert(std::make_unique<ctraits<Storage::fold>::Ttensym>(*(it.second)));
}
// UnfoldDecisionRule conversion from FoldDecisionRule
UnfoldDecisionRule::UnfoldDecisionRule(const FoldDecisionRule &fdr)
: DecisionRuleImpl<Storage::unfold>(ctraits<Storage::unfold>::Tpol(fdr.nrows(), fdr.nvars()),
fdr.ypart, fdr.nu, fdr.ysteady)
{
for (const auto &it : fdr)
insert(std::make_unique<ctraits<Storage::unfold>::Ttensym>(*(it.second)));
}
/* This runs simulations with an output to journal file. Note that we
report how many simulations had to be thrown out due to Nan or Inf. */
void
SimResults::simulate(int num_sim, const DecisionRule &dr, const Vector &start,
const TwoDMatrix &vcov, Journal &journal)
{
JournalRecordPair paa(journal);
paa << "Performing " << num_sim << " stochastic simulations for "
<< num_per << " periods burning " << num_burn << " initial periods" << endrec;
simulate(num_sim, dr, start, vcov);
int thrown = num_sim - data.size();
if (thrown > 0)
{
JournalRecord rec(journal);
rec << "I had to throw " << thrown << " simulations away due to Nan or Inf" << endrec;
}
}
/* This runs a given number of simulations by creating
SimulationWorker for each simulation and inserting them to the
thread group. */
void
SimResults::simulate(int num_sim, const DecisionRule &dr, const Vector &start,
const TwoDMatrix &vcov)
{
std::vector<RandomShockRealization> rsrs;
rsrs.reserve(num_sim);
sthread::detach_thread_group gr;
for (int i = 0; i < num_sim; i++)
{
RandomShockRealization sr(vcov, seed_generator::get_new_seed());
rsrs.push_back(sr);
gr.insert(std::make_unique<SimulationWorker>(*this, dr, DecisionRule::emethod::horner,
num_per+num_burn, start, rsrs.back()));
}
gr.run();
}
/* This adds the data with the realized shocks. It takes only periods
which are not to be burnt. If the data is not finite, the both data
and shocks are thrown away. */
bool
SimResults::addDataSet(const TwoDMatrix &d, const ExplicitShockRealization &sr, const ConstVector &st)
{
KORD_RAISE_IF(d.nrows() != num_y,
"Incompatible number of rows for SimResults::addDataSets");
KORD_RAISE_IF(d.ncols() != num_per+num_burn,
"Incompatible number of cols for SimResults::addDataSets");
bool ret = false;
if (d.isFinite())
{
data.emplace_back(d, num_burn, num_per);
shocks.emplace_back(ConstTwoDMatrix(sr.getShocks(), num_burn, num_per));
if (num_burn == 0)
start.emplace_back(st);
else
start.emplace_back(d.getCol(num_burn-1));
ret = true;
}
return ret;
}
void
SimResults::writeMat(const std::string &base, const std::string &lname) const
{
std::string matfile_name = base + ".mat";
mat_t *matfd = Mat_Create(matfile_name.c_str(), nullptr);
if (matfd)
{
writeMat(matfd, lname);
Mat_Close(matfd);
}
}
/* This save the results as matrices with given prefix and with index
appended. If there is only one matrix, the index is not appended. */
void
SimResults::writeMat(mat_t *fd, const std::string &lname) const
{
for (int i = 0; i < getNumSets(); i++)
{
std::string tmp = lname + "_data";
if (getNumSets() > 1)
tmp += std::to_string(i+1);
data[i].writeMat(fd, tmp);
}
}
void
SimResultsStats::simulate(int num_sim, const DecisionRule &dr,
const Vector &start,
const TwoDMatrix &vcov, Journal &journal)
{
SimResults::simulate(num_sim, dr, start, vcov, journal);
{
JournalRecordPair paa(journal);
paa << "Calculating means from the simulations." << endrec;
calcMean();
}
{
JournalRecordPair paa(journal);
paa << "Calculating covariances from the simulations." << endrec;
calcVcov();
}
}
/* Here we do not save the data itself, we save only mean and vcov. */
void
SimResultsStats::writeMat(mat_t *fd, const std::string &lname) const
{
ConstTwoDMatrix(num_y, 1, mean).writeMat(fd, lname + "_mean");;
vcov.writeMat(fd, lname + "_vcov");
}
void
SimResultsStats::calcMean()
{
mean.zeros();
if (data.size()*num_per > 0)
{
double mult = 1.0/data.size()/num_per;
for (const auto &i : data)
{
for (int j = 0; j < num_per; j++)
{
ConstVector col{i.getCol(j)};
mean.add(mult, col);
}
}
}
}
void
SimResultsStats::calcVcov()
{
if (data.size()*num_per > 1)
{
vcov.zeros();
double mult = 1.0/(data.size()*num_per - 1);
for (const auto &d : data)
for (int j = 0; j < num_per; j++)
for (int m = 0; m < num_y; m++)
for (int n = m; n < num_y; n++)
{
double s = (d.get(m, j)-mean[m])*(d.get(n, j)-mean[n]);
vcov.get(m, n) += mult*s;
if (m != n)
vcov.get(n, m) += mult*s;
}
}
else
vcov.infs();
}
void
SimResultsDynamicStats::simulate(int num_sim, const DecisionRule &dr,
const Vector &start,
const TwoDMatrix &vcov, Journal &journal)
{
SimResults::simulate(num_sim, dr, start, vcov, journal);
{
JournalRecordPair paa(journal);
paa << "Calculating means of the conditional simulations." << endrec;
calcMean();
}
{
JournalRecordPair paa(journal);
paa << "Calculating variances of the conditional simulations." << endrec;
calcVariance();
}
}
void
SimResultsDynamicStats::writeMat(mat_t *fd, const std::string &lname) const
{
mean.writeMat(fd, lname + "_cond_mean");
variance.writeMat(fd, lname + "_cond_variance");
}
void
SimResultsDynamicStats::calcMean()
{
mean.zeros();
if (data.size() > 0)
{
double mult = 1.0/data.size();
for (int j = 0; j < num_per; j++)
{
Vector meanj{mean.getCol(j)};
for (const auto &i : data)
{
ConstVector col{i.getCol(j)};
meanj.add(mult, col);
}
}
}
}
void
SimResultsDynamicStats::calcVariance()
{
if (data.size() > 1)
{
variance.zeros();
double mult = 1.0/(data.size()-1);
for (int j = 0; j < num_per; j++)
{
ConstVector meanj{mean.getCol(j)};
Vector varj{variance.getCol(j)};
for (const auto &i : data)
{
Vector col{i.getCol(j)};
col.add(-1.0, meanj);
for (int k = 0; k < col.length(); k++)
col[k] = col[k]*col[k];
varj.add(mult, col);
}
}
}
else
variance.infs();
}
void
SimResultsIRF::simulate(const DecisionRule &dr, Journal &journal)
{
JournalRecordPair paa(journal);
paa << "Performing " << control.getNumSets() << " IRF simulations for "
<< num_per << " periods; shock=" << ishock << ", impulse=" << imp << endrec;
simulate(dr);
int thrown = control.getNumSets() - data.size();
if (thrown > 0)
{
JournalRecord rec(journal);
rec << "I had to throw " << thrown
<< " simulations away due to Nan or Inf" << endrec;
}
calcMeans();
calcVariances();
}
void
SimResultsIRF::simulate(const DecisionRule &dr)
{
sthread::detach_thread_group gr;
for (int idata = 0; idata < control.getNumSets(); idata++)
gr.insert(std::make_unique<SimulationIRFWorker>(*this, dr, DecisionRule::emethod::horner,
num_per, idata, ishock, imp));
gr.run();
}
void
SimResultsIRF::calcMeans()
{
means.zeros();
if (data.size() > 0)
{
for (const auto &i : data)
means.add(1.0, i);
means.mult(1.0/data.size());
}
}
void
SimResultsIRF::calcVariances()
{
if (data.size() > 1)
{
variances.zeros();
for (const auto &i : data)
{
TwoDMatrix d(i);
d.add(-1.0, means);
for (int j = 0; j < d.nrows(); j++)
for (int k = 0; k < d.ncols(); k++)
variances.get(j, k) += d.get(j, k)*d.get(j, k);
d.mult(1.0/(data.size()-1));
}
}
else
variances.infs();
}
void
SimResultsIRF::writeMat(mat_t *fd, const std::string &lname) const
{
means.writeMat(fd, lname + "_mean");
variances.writeMat(fd, lname + "_var");
}
void
RTSimResultsStats::simulate(int num_sim, const DecisionRule &dr, const Vector &start,
const TwoDMatrix &v, Journal &journal)
{
JournalRecordPair paa(journal);
paa << "Performing " << num_sim << " real-time stochastic simulations for "
<< num_per << " periods" << endrec;
simulate(num_sim, dr, start, v);
mean = nc.getMean();
mean.add(1.0, dr.getSteady());
nc.getVariance(vcov);
if (thrown_periods > 0)
{
JournalRecord rec(journal);
rec << "I had to throw " << thrown_periods << " periods away due to Nan or Inf" << endrec;
JournalRecord rec1(journal);
rec1 << "This affected " << incomplete_simulations << " out of "
<< num_sim << " simulations" << endrec;
}
}
void
RTSimResultsStats::simulate(int num_sim, const DecisionRule &dr, const Vector &start,
const TwoDMatrix &vcov)
{
std::vector<RandomShockRealization> rsrs;
rsrs.reserve(num_sim);
sthread::detach_thread_group gr;
for (int i = 0; i < num_sim; i++)
{
RandomShockRealization sr(vcov, seed_generator::get_new_seed());
rsrs.push_back(sr);
gr.insert(std::make_unique<RTSimulationWorker>(*this, dr, DecisionRule::emethod::horner,
num_per, start, rsrs.back()));
}
gr.run();
}
void
RTSimResultsStats::writeMat(mat_t *fd, const std::string &lname)
{
ConstTwoDMatrix(nc.getDim(), 1, mean).writeMat(fd, lname + "_rt_mean");
vcov.writeMat(fd, lname + "_rt_vcov");
}
IRFResults::IRFResults(const DynamicModel &mod, const DecisionRule &dr,
const SimResults &control, std::vector<int> ili,
Journal &journal)
: model(mod), irf_list_ind(std::move(ili))
{
int num_per = control.getNumPer();
JournalRecordPair pa(journal);
pa << "Calculating IRFs against control for " << static_cast<int>(irf_list_ind.size()) << " shocks and for "
<< num_per << " periods" << endrec;
const TwoDMatrix &vcov = mod.getVcov();
for (int ishock : irf_list_ind)
{
double stderror = sqrt(vcov.get(ishock, ishock));
irf_res.emplace_back(control, model.numeq(), num_per,
ishock, stderror);
irf_res.emplace_back(control, model.numeq(), num_per,
ishock, -stderror);
}
for (unsigned int ii = 0; ii < irf_list_ind.size(); ii++)
{
irf_res[2*ii].simulate(dr, journal);
irf_res[2*ii+1].simulate(dr, journal);
}
}
void
IRFResults::writeMat(mat_t *fd, const std::string &prefix) const
{
for (unsigned int i = 0; i < irf_list_ind.size(); i++)
{
int ishock = irf_list_ind[i];
auto shockname = model.getExogNames().getName(ishock);
irf_res[2*i].writeMat(fd, prefix + "_irfp_" + shockname);
irf_res[2*i+1].writeMat(fd, prefix + "_irfm_" + shockname);
}
}
void
SimulationWorker::operator()(std::mutex &mut)
{
ExplicitShockRealization esr(sr, np);
TwoDMatrix m{dr.simulate(em, np, st, esr)};
{
std::unique_lock<std::mutex> lk{mut};
res.addDataSet(m, esr, st);
}
}
/* Here we create a new instance of ExplicitShockRealization of the
corresponding control, add the impulse, and simulate. */
void
SimulationIRFWorker::operator()(std::mutex &mut)
{
ExplicitShockRealization esr(res.control.getShocks(idata));
esr.addToShock(ishock, 0, imp);
TwoDMatrix m{dr.simulate(em, np, res.control.getStart(idata), esr)};
m.add(-1.0, res.control.getData(idata));
{
std::unique_lock<std::mutex> lk{mut};
res.addDataSet(m, esr, res.control.getStart(idata));
}
}
void
RTSimulationWorker::operator()(std::mutex &mut)
{
NormalConj nc(res.nc.getDim());
const PartitionY &ypart = dr.getYPart();
int nu = dr.nexog();
const Vector &ysteady = dr.getSteady();
// initialize vectors and subvectors for simulation
Vector dyu(ypart.nys()+nu);
ConstVector ystart_pred(ystart, ypart.nstat, ypart.nys());
ConstVector ysteady_pred(ysteady, ypart.nstat, ypart.nys());
Vector dy(dyu, 0, ypart.nys());
Vector u(dyu, ypart.nys(), nu);
Vector y(nc.getDim());
ConstVector ypred(y, ypart.nstat, ypart.nys());
// simulate the first real-time period
int ip = 0;
dy = ystart_pred;
dy.add(-1.0, ysteady_pred);
sr.get(ip, u);
dr.eval(em, y, dyu);
if (ip >= res.num_burn)
nc.update(y);
// simulate other real-time periods
while (y.isFinite() && ip < res.num_burn + res.num_per)
{
ip++;
dy = ypred;
sr.get(ip, u);
dr.eval(em, y, dyu);
if (ip >= res.num_burn)
nc.update(y);
}
{
std::unique_lock<std::mutex> lk{mut};
res.nc.update(nc);
if (res.num_per-ip > 0)
{
res.incomplete_simulations++;
res.thrown_periods += res.num_per-ip;
}
}
}
/* This calculates factorization FFᵀ=V in the Cholesky way. It does
not work for semidefinite matrices. */
void
RandomShockRealization::choleskyFactor(const ConstTwoDMatrix &v)
{
factor = v;
lapack_int rows = factor.nrows(), lda = factor.getLD();
for (int i = 0; i < rows; i++)
for (int j = i+1; j < rows; j++)
factor.get(i, j) = 0.0;
lapack_int info;
dpotrf("L", &rows, factor.base(), &lda, &info);
KORD_RAISE_IF(info != 0,
"Info!=0 in RandomShockRealization::choleskyFactor");
}
/* This calculates FFᵀ=V factorization by symmetric Schur
decomposition. It works for semidefinite matrices. */
void
RandomShockRealization::schurFactor(const ConstTwoDMatrix &v)
{
SymSchurDecomp(v).getFactor(factor);
}
void
RandomShockRealization::get(int n, Vector &out)
{
KORD_RAISE_IF(out.length() != numShocks(),
"Wrong length of out vector in RandomShockRealization::get");
Vector d(out.length());
for (int i = 0; i < d.length(); i++)
d[i] = dis(mtwister);
out.zeros();
factor.multaVec(out, ConstVector(d));
}
ExplicitShockRealization::ExplicitShockRealization(ShockRealization &sr,
int num_per)
: shocks(sr.numShocks(), num_per)
{
for (int j = 0; j < num_per; j++)
{
Vector jcol{shocks.getCol(j)};
sr.get(j, jcol);
}
}
void
ExplicitShockRealization::get(int n, Vector &out)
{
KORD_RAISE_IF(out.length() != numShocks(),
"Wrong length of out vector in ExplicitShockRealization::get");
int i = n % shocks.ncols();
ConstVector icol{shocks.getCol(i)};
out = icol;
}
void
ExplicitShockRealization::addToShock(int ishock, int iper, double val)
{
KORD_RAISE_IF(ishock < 0 || ishock > numShocks(),
"Wrong index of shock in ExplicitShockRealization::addToShock");
int j = iper % shocks.ncols();
shocks.get(ishock, j) += val;
}
void
GenShockRealization::get(int n, Vector &out)
{
KORD_RAISE_IF(out.length() != numShocks(),
"Wrong length of out vector in GenShockRealization::get");
ExplicitShockRealization::get(n, out);
Vector r(numShocks());
RandomShockRealization::get(n, r);
for (int j = 0; j < numShocks(); j++)
if (!std::isfinite(out[j]))
out[j] = r[j];
}

View File

@ -1,697 +0,0 @@
@q $Id: decision_rule.cweb 1896 2008-06-24 04:01:05Z kamenik $ @>
@q Copyright 2004, Ondra Kamenik @>
@ Start of {\tt decision\_rule.cpp} file.
@c
#include "kord_exception.h"
#include "decision_rule.h"
#include "dynamic_model.h"
#include "SymSchurDecomp.h"
#include <dynlapack.h>
#include <limits>
template <>
int DRFixPoint<KOrder::fold>::max_iter = 10000;
template <>
int DRFixPoint<KOrder::unfold>::max_iter = 10000;
template <>
double DRFixPoint<KOrder::fold>::tol = 1.e-10;
template <>
double DRFixPoint<KOrder::unfold>::tol = 1.e-10;
template <>
int DRFixPoint<KOrder::fold>::max_newton_iter = 50;
template <>
int DRFixPoint<KOrder::unfold>::max_newton_iter = 50;
template <>
int DRFixPoint<KOrder::fold>::newton_pause = 100;
template <>
int DRFixPoint<KOrder::unfold>::newton_pause = 100;
@#
@<|FoldDecisionRule| conversion from |UnfoldDecisionRule|@>;
@<|UnfoldDecisionRule| conversion from |FoldDecisionRule|@>;
@<|SimResults| destructor@>;
@<|SimResults::simulate| code1@>;
@<|SimResults::simulate| code2@>;
@<|SimResults::addDataSet| code@>;
@<|SimResults::writeMat| code1@>;
@<|SimResults::writeMat| code2@>;
@<|SimResultsStats::simulate| code@>;
@<|SimResultsStats::writeMat| code@>;
@<|SimResultsStats::calcMean| code@>;
@<|SimResultsStats::calcVcov| code@>;
@<|SimResultsDynamicStats::simulate| code@>;
@<|SimResultsDynamicStats::writeMat| code@>;
@<|SimResultsDynamicStats::calcMean| code@>;
@<|SimResultsDynamicStats::calcVariance| code@>;
@<|SimResultsIRF::simulate| code1@>;
@<|SimResultsIRF::simulate| code2@>;
@<|SimResultsIRF::calcMeans| code@>;
@<|SimResultsIRF::calcVariances| code@>;
@<|SimResultsIRF::writeMat| code@>;
@<|RTSimResultsStats::simulate| code1@>;
@<|RTSimResultsStats::simulate| code2@>;
@<|RTSimResultsStats::writeMat| code@>;
@<|IRFResults| constructor@>;
@<|IRFResults| destructor@>;
@<|IRFResults::writeMat| code@>;
@<|SimulationWorker::operator()()| code@>;
@<|SimulationIRFWorker::operator()()| code@>;
@<|RTSimulationWorker::operator()()| code@>;
@<|RandomShockRealization::choleskyFactor| code@>;
@<|RandomShockRealization::schurFactor| code@>;
@<|RandomShockRealization::get| code@>;
@<|ExplicitShockRealization| constructor code@>;
@<|ExplicitShockRealization::get| code@>;
@<|ExplicitShockRealization::addToShock| code@>;
@<|GenShockRealization::get| code@>;
@
@<|FoldDecisionRule| conversion from |UnfoldDecisionRule|@>=
FoldDecisionRule::FoldDecisionRule(const UnfoldDecisionRule& udr)
: DecisionRuleImpl<KOrder::fold>(ctraits<KOrder::fold>::Tpol(udr.nrows(), udr.nvars()),
udr.ypart, udr.nu, udr.ysteady)
{
for (ctraits<KOrder::unfold>::Tpol::const_iterator it = udr.begin();
it != udr.end(); ++it) {
insert(new ctraits<KOrder::fold>::Ttensym(*((*it).second)));
}
}
@
@<|UnfoldDecisionRule| conversion from |FoldDecisionRule|@>=
UnfoldDecisionRule::UnfoldDecisionRule(const FoldDecisionRule& fdr)
: DecisionRuleImpl<KOrder::unfold>(ctraits<KOrder::unfold>::Tpol(fdr.nrows(), fdr.nvars()),
fdr.ypart, fdr.nu, fdr.ysteady)
{
for (ctraits<KOrder::fold>::Tpol::const_iterator it = fdr.begin();
it != fdr.end(); ++it) {
insert(new ctraits<KOrder::unfold>::Ttensym(*((*it).second)));
}
}
@
@<|SimResults| destructor@>=
SimResults::~SimResults()
{
for (int i = 0; i < getNumSets(); i++) {
delete data[i];
delete shocks[i];
}
}
@ This runs simulations with an output to journal file. Note that we
report how many simulations had to be thrown out due to Nan or Inf.
@<|SimResults::simulate| code1@>=
void SimResults::simulate(int num_sim, const DecisionRule& dr, const Vector& start,
const TwoDMatrix& vcov, Journal& journal)
{
JournalRecordPair paa(journal);
paa << "Performing " << num_sim << " stochastic simulations for "
<< num_per << " periods burning " << num_burn << " initial periods" << endrec;
simulate(num_sim, dr, start, vcov);
int thrown = num_sim - data.size();
if (thrown > 0) {
JournalRecord rec(journal);
rec << "I had to throw " << thrown << " simulations away due to Nan or Inf" << endrec;
}
}
@ This runs a given number of simulations by creating
|SimulationWorker| for each simulation and inserting them to the
thread group.
@<|SimResults::simulate| code2@>=
void SimResults::simulate(int num_sim, const DecisionRule& dr, const Vector& start,
const TwoDMatrix& vcov)
{
std::vector<RandomShockRealization> rsrs;
rsrs.reserve(num_sim);
THREAD_GROUP gr;
for (int i = 0; i < num_sim; i++) {
RandomShockRealization sr(vcov, system_random_generator.int_uniform());
rsrs.push_back(sr);
THREAD* worker = new
SimulationWorker(*this, dr, DecisionRule::horner,
num_per+num_burn, start, rsrs.back());
gr.insert(worker);
}
gr.run();
}
@ This adds the data with the realized shocks. It takes only periods
which are not to be burnt. If the data is not finite, the both data
and shocks are thrown away.
@<|SimResults::addDataSet| code@>=
bool SimResults::addDataSet(TwoDMatrix* d, ExplicitShockRealization* sr)
{
KORD_RAISE_IF(d->nrows() != num_y,
"Incompatible number of rows for SimResults::addDataSets");
KORD_RAISE_IF(d->ncols() != num_per+num_burn,
"Incompatible number of cols for SimResults::addDataSets");
bool ret = false;
if (d->isFinite()) {
data.push_back(new TwoDMatrix((const TwoDMatrix&)(*d),num_burn,num_per));
shocks.push_back(new ExplicitShockRealization(
ConstTwoDMatrix(sr->getShocks(),num_burn,num_per)));
ret = true;
}
delete d;
delete sr;
return ret;
}
@
@<|SimResults::writeMat| code1@>=
void SimResults::writeMat(const char* base, const char* lname) const
{
char matfile_name[100];
sprintf(matfile_name, "%s.mat", base);
mat_t* matfd = Mat_Create(matfile_name, NULL);
if (matfd != NULL) {
writeMat(matfd, lname);
Mat_Close(matfd);
}
}
@ This save the results as matrices with given prefix and with index
appended. If there is only one matrix, the index is not appended.
@<|SimResults::writeMat| code2@>=
void SimResults::writeMat(mat_t* fd, const char* lname) const
{
char tmp[100];
for (int i = 0; i < getNumSets(); i++) {
if (getNumSets() > 1)
sprintf(tmp, "%s_data%d", lname, i+1);
else
sprintf(tmp, "%s_data", lname);
ConstTwoDMatrix m(*(data[i]));
m.writeMat(fd, tmp);
}
}
@
@<|SimResultsStats::simulate| code@>=
void SimResultsStats::simulate(int num_sim, const DecisionRule& dr,
const Vector& start,
const TwoDMatrix& vcov, Journal& journal)
{
SimResults::simulate(num_sim, dr, start, vcov, journal);
{
JournalRecordPair paa(journal);
paa << "Calculating means from the simulations." << endrec;
calcMean();
}
{
JournalRecordPair paa(journal);
paa << "Calculating covariances from the simulations." << endrec;
calcVcov();
}
}
@ Here we do not save the data itself, we save only mean and vcov.
@<|SimResultsStats::writeMat| code@>=
void SimResultsStats::writeMat(mat_t* fd, const char* lname) const
{
char tmp[100];
sprintf(tmp, "%s_mean", lname);
ConstTwoDMatrix m(num_y, 1, mean.base());
m.writeMat(fd, tmp);
sprintf(tmp, "%s_vcov", lname);
ConstTwoDMatrix(vcov).writeMat(fd, tmp);
}
@
@<|SimResultsStats::calcMean| code@>=
void SimResultsStats::calcMean()
{
mean.zeros();
if (data.size()*num_per > 0) {
double mult = 1.0/data.size()/num_per;
for (unsigned int i = 0; i < data.size(); i++) {
for (int j = 0; j < num_per; j++) {
ConstVector col(*data[i], j);
mean.add(mult, col);
}
}
}
}
@
@<|SimResultsStats::calcVcov| code@>=
void SimResultsStats::calcVcov()
{
if (data.size()*num_per > 1) {
vcov.zeros();
double mult = 1.0/(data.size()*num_per - 1);
for (unsigned int i = 0; i < data.size(); i++) {
const TwoDMatrix& d = *(data[i]);
for (int j = 0; j < num_per; j++) {
for (int m = 0; m < num_y; m++) {
for (int n = m; n < num_y; n++) {
double s = (d.get(m,j)-mean[m])*(d.get(n,j)-mean[n]);
vcov.get(m,n) += mult*s;
if (m != n)
vcov.get(n,m) += mult*s;
}
}
}
}
} else {
vcov.infs();
}
}
@
@<|SimResultsDynamicStats::simulate| code@>=
void SimResultsDynamicStats::simulate(int num_sim, const DecisionRule& dr,
const Vector& start,
const TwoDMatrix& vcov, Journal& journal)
{
SimResults::simulate(num_sim, dr, start, vcov, journal);
{
JournalRecordPair paa(journal);
paa << "Calculating means of the conditional simulations." << endrec;
calcMean();
}
{
JournalRecordPair paa(journal);
paa << "Calculating variances of the conditional simulations." << endrec;
calcVariance();
}
}
@
@<|SimResultsDynamicStats::writeMat| code@>=
void SimResultsDynamicStats::writeMat(mat_t* fd, const char* lname) const
{
char tmp[100];
sprintf(tmp, "%s_cond_mean", lname);
ConstTwoDMatrix(mean).writeMat(fd, tmp);
sprintf(tmp, "%s_cond_variance", lname);
ConstTwoDMatrix(variance).writeMat(fd, tmp);
}
@
@<|SimResultsDynamicStats::calcMean| code@>=
void SimResultsDynamicStats::calcMean()
{
mean.zeros();
if (data.size() > 0) {
double mult = 1.0/data.size();
for (int j = 0; j < num_per; j++) {
Vector meanj(mean, j);
for (unsigned int i = 0; i < data.size(); i++) {
ConstVector col(*data[i], j);
meanj.add(mult, col);
}
}
}
}
@
@<|SimResultsDynamicStats::calcVariance| code@>=
void SimResultsDynamicStats::calcVariance()
{
if (data.size() > 1) {
variance.zeros();
double mult = 1.0/(data.size()-1);
for (int j = 0; j < num_per; j++) {
ConstVector meanj(mean, j);
Vector varj(variance, j);
for (int i = 0; i < (int)data.size(); i++) {
Vector col(ConstVector((*data[i]), j));
col.add(-1.0, meanj);
for (int k = 0; k < col.length(); k++)
col[k] = col[k]*col[k];
varj.add(mult, col);
}
}
} else {
variance.infs();
}
}
@
@<|SimResultsIRF::simulate| code1@>=
void SimResultsIRF::simulate(const DecisionRule& dr, Journal& journal)
{
JournalRecordPair paa(journal);
paa << "Performing " << control.getNumSets() << " IRF simulations for "
<< num_per << " periods; shock=" << ishock << ", impulse=" << imp << endrec;
simulate(dr);
int thrown = control.getNumSets() - data.size();
if (thrown > 0) {
JournalRecord rec(journal);
rec << "I had to throw " << thrown
<< " simulations away due to Nan or Inf" << endrec;
}
calcMeans();
calcVariances();
}
@
@<|SimResultsIRF::simulate| code2@>=
void SimResultsIRF::simulate(const DecisionRule& dr)
{
THREAD_GROUP gr;
for (int idata = 0; idata < control.getNumSets(); idata++) {
THREAD* worker = new
SimulationIRFWorker(*this, dr, DecisionRule::horner,
num_per, idata, ishock, imp);
gr.insert(worker);
}
gr.run();
}
@
@<|SimResultsIRF::calcMeans| code@>=
void SimResultsIRF::calcMeans()
{
means.zeros();
if (data.size() > 0) {
for (unsigned int i = 0; i < data.size(); i++)
means.add(1.0, *(data[i]));
means.mult(1.0/data.size());
}
}
@
@<|SimResultsIRF::calcVariances| code@>=
void SimResultsIRF::calcVariances()
{
if (data.size() > 1) {
variances.zeros();
for (unsigned int i = 0; i < data.size(); i++) {
TwoDMatrix d((const TwoDMatrix&)(*(data[i])));
d.add(-1.0, means);
for (int j = 0; j < d.nrows(); j++)
for (int k = 0; k < d.ncols(); k++)
variances.get(j,k) += d.get(j,k)*d.get(j,k);
d.mult(1.0/(data.size()-1));
}
} else {
variances.infs();
}
}
@
@<|SimResultsIRF::writeMat| code@>=
void SimResultsIRF::writeMat(mat_t* fd, const char* lname) const
{
char tmp[100];
sprintf(tmp, "%s_mean", lname);
means.writeMat(fd, tmp);
sprintf(tmp, "%s_var", lname);
variances.writeMat(fd, tmp);
}
@
@<|RTSimResultsStats::simulate| code1@>=
void RTSimResultsStats::simulate(int num_sim, const DecisionRule& dr, const Vector& start,
const TwoDMatrix& v, Journal& journal)
{
JournalRecordPair paa(journal);
paa << "Performing " << num_sim << " real-time stochastic simulations for "
<< num_per << " periods" << endrec;
simulate(num_sim, dr, start, v);
mean = nc.getMean();
mean.add(1.0, dr.getSteady());
nc.getVariance(vcov);
if (thrown_periods > 0) {
JournalRecord rec(journal);
rec << "I had to throw " << thrown_periods << " periods away due to Nan or Inf" << endrec;
JournalRecord rec1(journal);
rec1 << "This affected " << incomplete_simulations << " out of "
<< num_sim << " simulations" << endrec;
}
}
@
@<|RTSimResultsStats::simulate| code2@>=
void RTSimResultsStats::simulate(int num_sim, const DecisionRule& dr, const Vector& start,
const TwoDMatrix& vcov)
{
std::vector<RandomShockRealization> rsrs;
rsrs.reserve(num_sim);
THREAD_GROUP gr;
for (int i = 0; i < num_sim; i++) {
RandomShockRealization sr(vcov, system_random_generator.int_uniform());
rsrs.push_back(sr);
THREAD* worker = new
RTSimulationWorker(*this, dr, DecisionRule::horner,
num_per, start, rsrs.back());
gr.insert(worker);
}
gr.run();
}
@
@<|RTSimResultsStats::writeMat| code@>=
void RTSimResultsStats::writeMat(mat_t* fd, const char* lname)
{
char tmp[100];
sprintf(tmp, "%s_rt_mean", lname);
ConstTwoDMatrix m(nc.getDim(), 1, mean.base());
m.writeMat(fd, tmp);
sprintf(tmp, "%s_rt_vcov", lname);
ConstTwoDMatrix(vcov).writeMat(fd, tmp);
}
@
@<|IRFResults| constructor@>=
IRFResults::IRFResults(const DynamicModel& mod, const DecisionRule& dr,
const SimResults& control, const vector<int>& ili,
Journal& journal)
: model(mod), irf_list_ind(ili)
{
int num_per = control.getNumPer();
JournalRecordPair pa(journal);
pa << "Calculating IRFs against control for " << (int)irf_list_ind.size() << " shocks and for "
<< num_per << " periods" << endrec;
const TwoDMatrix& vcov = mod.getVcov();
for (unsigned int ii = 0; ii < irf_list_ind.size(); ii++) {
int ishock = irf_list_ind[ii];
double stderror = sqrt(vcov.get(ishock,ishock));
irf_res.push_back(new SimResultsIRF(control, model.numeq(), num_per,
ishock, stderror));
irf_res.push_back(new SimResultsIRF(control, model.numeq(), num_per,
ishock, -stderror));
}
for (unsigned int ii = 0; ii < irf_list_ind.size(); ii++) {
irf_res[2*ii]->simulate(dr, journal);
irf_res[2*ii+1]->simulate(dr, journal);
}
}
@
@<|IRFResults| destructor@>=
IRFResults::~IRFResults()
{
for (unsigned int i = 0; i < irf_res.size(); i++)
delete irf_res[i];
}
@
@<|IRFResults::writeMat| code@>=
void IRFResults::writeMat(mat_t* fd, const char* prefix) const
{
for (unsigned int i = 0; i < irf_list_ind.size(); i++) {
char tmp[100];
int ishock = irf_list_ind[i];
const char* shockname = model.getExogNames().getName(ishock);
sprintf(tmp, "%s_irfp_%s", prefix, shockname);
irf_res[2*i]->writeMat(fd, tmp);
sprintf(tmp, "%s_irfm_%s", prefix, shockname);
irf_res[2*i+1]->writeMat(fd, tmp);
}
}
@
@<|SimulationWorker::operator()()| code@>=
void SimulationWorker::operator()()
{
ExplicitShockRealization* esr = new ExplicitShockRealization(sr, np);
TwoDMatrix* m = dr.simulate(em, np, st, *esr);
{
SYNCHRO syn(&res, "simulation");
res.addDataSet(m, esr);
}
}
@ Here we create a new instance of |ExplicitShockRealization| of the
corresponding control, add the impulse, and simulate.
@<|SimulationIRFWorker::operator()()| code@>=
void SimulationIRFWorker::operator()()
{
ExplicitShockRealization* esr =
new ExplicitShockRealization(res.control.getShocks(idata));
esr->addToShock(ishock, 0, imp);
const TwoDMatrix& data = res.control.getData(idata);
ConstVector st(data, res.control.getNumBurn());
TwoDMatrix* m = dr.simulate(em, np, st, *esr);
m->add(-1.0, res.control.getData(idata));
{
SYNCHRO syn(&res, "simulation");
res.addDataSet(m, esr);
}
}
@
@<|RTSimulationWorker::operator()()| code@>=
void RTSimulationWorker::operator()()
{
NormalConj nc(res.nc.getDim());
const PartitionY& ypart = dr.getYPart();
int nu = dr.nexog();
const Vector& ysteady = dr.getSteady();
@<initialize vectors and subvectors for simulation@>;
@<simulate the first real-time period@>;
@<simulate other real-time periods@>;
{
SYNCHRO syn(&res, "rtsimulation");
res.nc.update(nc);
if (res.num_per-ip > 0) {
res.incomplete_simulations++;
res.thrown_periods += res.num_per-ip;
}
}
}
@
@<initialize vectors and subvectors for simulation@>=
Vector dyu(ypart.nys()+nu);
ConstVector ystart_pred(ystart, ypart.nstat, ypart.nys());
ConstVector ysteady_pred(ysteady, ypart.nstat, ypart.nys());
Vector dy(dyu, 0, ypart.nys());
Vector u(dyu, ypart.nys(), nu);
Vector y(nc.getDim());
ConstVector ypred(y, ypart.nstat, ypart.nys());
@
@<simulate the first real-time period@>=
int ip = 0;
dy = ystart_pred;
dy.add(-1.0, ysteady_pred);
sr.get(ip, u);
dr.eval(em, y, dyu);
if (ip >= res.num_burn)
nc.update(y);
@
@<simulate other real-time periods@>=
while (y.isFinite() && ip < res.num_burn + res.num_per) {
ip++;
dy = ypred;
sr.get(ip, u);
dr.eval(em, y, dyu);
if (ip >= res.num_burn)
nc.update(y);
}
@ This calculates factorization $FF^T=V$ in the Cholesky way. It does
not work for semidefinite matrices.
@<|RandomShockRealization::choleskyFactor| code@>=
void RandomShockRealization::choleskyFactor(const TwoDMatrix& v)
{
factor = v;
lapack_int rows = factor.nrows();
for (int i = 0; i < rows; i++)
for (int j = i+1; j < rows; j++)
factor.get(i,j) = 0.0;
lapack_int info;
dpotrf("L", &rows, factor.base(), &rows, &info);
KORD_RAISE_IF(info != 0,
"Info!=0 in RandomShockRealization::choleskyFactor");
}
@ This calculates $FF^T=V$ factorization by symmetric Schur
decomposition. It works for semidifinite matrices.
@<|RandomShockRealization::schurFactor| code@>=
void RandomShockRealization::schurFactor(const TwoDMatrix& v)
{
SymSchurDecomp ssd(v);
ssd.getFactor(factor);
}
@
@<|RandomShockRealization::get| code@>=
void RandomShockRealization::get(int n, Vector& out)
{
KORD_RAISE_IF(out.length() != numShocks(),
"Wrong length of out vector in RandomShockRealization::get");
Vector d(out.length());
for (int i = 0; i < d.length(); i++) {
d[i] = mtwister.normal();
}
out.zeros();
factor.multaVec(out, ConstVector(d));
}
@
@<|ExplicitShockRealization| constructor code@>=
ExplicitShockRealization::ExplicitShockRealization(ShockRealization& sr,
int num_per)
: shocks(sr.numShocks(), num_per)
{
for (int j = 0; j < num_per; j++) {
Vector jcol(shocks, j);
sr.get(j, jcol);
}
}
@
@<|ExplicitShockRealization::get| code@>=
void ExplicitShockRealization::get(int n, Vector& out)
{
KORD_RAISE_IF(out.length() != numShocks(),
"Wrong length of out vector in ExplicitShockRealization::get");
int i = n % shocks.ncols();
ConstVector icol(shocks, i);
out = icol;
}
@
@<|ExplicitShockRealization::addToShock| code@>=
void ExplicitShockRealization::addToShock(int ishock, int iper, double val)
{
KORD_RAISE_IF(ishock < 0 || ishock > numShocks(),
"Wrong index of shock in ExplicitShockRealization::addToShock");
int j = iper % shocks.ncols();
shocks.get(ishock, j) += val;
}
@
@<|GenShockRealization::get| code@>=
void GenShockRealization::get(int n, Vector& out)
{
KORD_RAISE_IF(out.length() != numShocks(),
"Wrong length of out vector in GenShockRealization::get");
ExplicitShockRealization::get(n, out);
Vector r(numShocks());
RandomShockRealization::get(n, r);
for (int j = 0; j < numShocks(); j++)
if (! isfinite(out[j]))
out[j] = r[j];
}
@ End of {\tt decision\_rule.cpp} file.

File diff suppressed because it is too large Load Diff

View File

@ -1,999 +0,0 @@
@q $Id: decision_rule.hweb 2336 2009-01-14 10:37:02Z kamenik $ @>
@q Copyright 2004, Ondra Kamenik @>
@*2 Decision rule and simulation. Start of {\tt decision\_rule.h} file.
The main purpose of this file is a decision rule representation which
can run a simulation. So we define an interface for classes providing
realizations of random shocks, and define the class
|DecisionRule|. The latter basically takes tensor container of
derivatives of policy rules, and adds them up with respect to
$\sigma$. The class allows to specify the $\sigma$ different from $1$.
In addition, we provide classes for running simulations and storing
the results, calculating some statistics and generating IRF. The class
|DRFixPoint| allows for calculation of the fix point of a given
decision rule.
@s DecisionRule int
@s DecisionRuleImpl int
@s FoldDecisionRule int
@s UnfoldDecisionRule int
@s ShockRealization int
@s DRFixPoint int
@s SimResults int
@s SimResultsStats int
@s SimResultsDynamicStats int
@s RTSimResultsStats int
@s SimResultsIRF int
@s IRFResults int
@s SimulationWorker int
@s RTSimulationWorker int
@s SimulationIRFWorker int
@s RandomShockRealization int
@s ExplicitShockRealization int
@s GenShockRealization int
@s IRFShockRealization int
@c
#ifndef DECISION_RULE_H
#define DECISION_RULE_H
#include <matio.h>
#include "kord_exception.h"
#include "korder.h"
#include "normal_conjugate.h"
#include "mersenne_twister.h"
@<|ShockRealization| class declaration@>;
@<|DecisionRule| class declaration@>;
@<|DecisionRuleImpl| class declaration@>;
@<|FoldDecisionRule| class declaration@>;
@<|UnfoldDecisionRule| class declaration@>;
@<|DRFixPoint| class declaration@>;
@<|SimResults| class declaration@>;
@<|SimResultsStats| class declaration@>;
@<|SimResultsDynamicStats| class declaration@>;
@<|SimResultsIRF| class declaration@>;
@<|RTSimResultsStats| class declaration@>;
@<|IRFResults| class declaration@>;
@<|SimulationWorker| class declaration@>;
@<|SimulationIRFWorker| class declaration@>;
@<|RTSimulationWorker| class declaration@>;
@<|RandomShockRealization| class declaration@>;
@<|ExplicitShockRealization| class declaration@>;
@<|GenShockRealization| class declaration@>;
#endif
@ This is a general interface to a shock realizations. The interface
has only one method returning the shock realizations at the given
time. This method is not constant, since it may change a state of the
object.
@<|ShockRealization| class declaration@>=
class ShockRealization {
public:@;
virtual ~ShockRealization()@+ {}
virtual void get(int n, Vector& out) =0;
virtual int numShocks() const =0;
};
@ This class is an abstract interface to decision rule. Its main
purpose is to define a common interface for simulation of a decision
rule. We need only a simulate, evaluate, cetralized clone and output
method. The |simulate| method simulates the rule for a given
realization of the shocks. |eval| is a primitive evaluation (it takes
a vector of state variables (predetermined, both and shocks) and
returns the next period variables. Both input and output are in
deviations from the rule's steady. |evaluate| method makes only one
step of simulation (in terms of absolute values, not
deviations). |centralizedClone| returns a new copy of the decision
rule, which is centralized about provided fix-point. And finally
|writeMat| writes the decision rule to the MAT file.
@<|DecisionRule| class declaration@>=
class DecisionRule {
public:@;
enum emethod {@+ horner, trad @+};
virtual ~DecisionRule()@+ {}
virtual TwoDMatrix* simulate(emethod em, int np, const Vector& ystart,
ShockRealization& sr) const =0;
virtual void eval(emethod em, Vector& out, const ConstVector& v) const =0;
virtual void evaluate(emethod em, Vector& out, const ConstVector& ys,
const ConstVector& u) const =0;
virtual void writeMat(mat_t* fd, const char* prefix) const =0;
virtual DecisionRule* centralizedClone(const Vector& fixpoint) const =0;
virtual const Vector& getSteady() const =0;
virtual int nexog() const =0;
virtual const PartitionY& getYPart() const =0;
};
@ The main purpose of this class is to implement |DecisionRule|
interface, which is a simulation. To be able to do this we have to
know the partitioning of state vector $y$ since we will need to pick
only predetermined part $y^*$. Also, we need to know the steady state.
The decision rule will take the form: $$y_t-\bar
y=\sum_{i=0}^n\left[g_{(yu)^i}\right]_{\alpha_1\ldots\alpha_i}\prod_{m=1}^i
\left[\matrix{y^*_{t-1}-\bar y^*\cr u_t}\right]^{\alpha_m},$$ where
the tensors $\left[g_{(yu)^i}\right]$ are tensors of the constructed
container, and $\bar y$ is the steady state.
If we know the fix point of the rule (conditional zero shocks)
$\tilde y$, the rule can be transformed to so called ``centralized''
form. This is very similar to the form above but the zero dimensional
tensor is zero:
$$y_t-\tilde y=\sum_{i=1}^n
\left[\tilde g_{(yu)^i}\right]_{\alpha_1\ldots\alpha_i}\prod_{m=1}^i
\left[\matrix{y^*_{t-1}-\tilde y^*\cr u_t}\right]^{\alpha_m}.$$
We provide a method and a constructor to transform a rule to the centralized form.
The class is templated, the template argument is either |KOrder::fold|
or |KOrder::unfold|. So, there are two implementations of |DecisionRule| interface.
@<|DecisionRuleImpl| class declaration@>=
template <int t>
class DecisionRuleImpl : public ctraits<t>::Tpol, public DecisionRule {
protected:@;
typedef typename ctraits<t>::Tpol _Tparent;
const Vector ysteady;
const PartitionY ypart;
const int nu;
public:@;
DecisionRuleImpl(const _Tparent& pol, const PartitionY& yp, int nuu,
const Vector& ys)
: ctraits<t>::Tpol(pol), ysteady(ys), ypart(yp), nu(nuu)@+ {}
DecisionRuleImpl(_Tparent& pol, const PartitionY& yp, int nuu,
const Vector& ys)
: ctraits<t>::Tpol(0, yp.ny(), pol), ysteady(ys), ypart(yp),
nu(nuu)@+ {}
DecisionRuleImpl(const _Tg& g, const PartitionY& yp, int nuu,
const Vector& ys, double sigma)
: ctraits<t>::Tpol(yp.ny(), yp.nys()+nuu), ysteady(ys), ypart(yp), nu(nuu)
{@+ fillTensors(g, sigma);@+}
DecisionRuleImpl(const DecisionRuleImpl<t>& dr, const ConstVector& fixpoint)
: ctraits<t>::Tpol(dr.ypart.ny(), dr.ypart.nys()+dr.nu),
ysteady(fixpoint), ypart(dr.ypart), nu(dr.nu)
{@+ centralize(dr);@+}
const Vector& getSteady() const
{@+ return ysteady;@+}
@<|DecisionRuleImpl::simulate| code@>;
@<|DecisionRuleImpl::evaluate| code@>;
@<|DecisionRuleImpl::centralizedClone| code@>;
@<|DecisionRuleImpl::writeMat| code@>;
int nexog() const
{@+ return nu;@+}
const PartitionY& getYPart() const
{@+ return ypart;}
protected:@;
@<|DecisionRuleImpl::fillTensors| code@>;
@<|DecisionRuleImpl::centralize| code@>;
@<|DecisionRuleImpl::eval| code@>;
};
@ Here we have to fill the tensor polynomial. This involves two
separated actions. First is to evaluate the approximation at a given
$\sigma$, the second is to compile the tensors $[g_{{(yu)}^{i+j}}]$ from
$[g_{y^iu^j}]$. The first action is done here, the second is done by
method |addSubTensor| of a full symmetry tensor.
The way how the evaluation is done is described here:
The $q-$order approximation to the solution can be written as:
$$
\eqalign{
y_t-\bar y &= \sum_{l=1}^q{1\over l!}\left[\sum_{i+j+k=l}
\left(\matrix{l\cr i,j,k}\right)\left[g_{y^iu^j\sigma^k}\right]
_{\alpha_1\ldots\alpha_j\beta_1\ldots\beta_j}
\prod_{m=1}^i[y^*_{t-1}-\bar y^*]^{\alpha_m}
\prod_{n=1}^j[u_t]^{\beta_m}\sigma^k\right]\cr
&= \sum_{l=1}^q\left[\sum_{i+j\leq l}\left(\matrix{i+j\cr i}\right)
\left[\sum_{k=0}^{l-i-j}{1\over l!}
\left(\matrix{l\cr k}\right)\left[g_{y^iu^j\sigma^k}\right]\sigma^k\right]
\prod_{m=1}^i[y^*_{t-1}-\bar y^*]^{\alpha_m}
\prod_{n=1}^j[u_t]^{\beta_m}\sigma^k\right]
}
$$
This means that for each $i+j+k=l$ we have to add
$${1\over l!}\left(\matrix{l\cr
k}\right)\left[g_{y^iu^j\sigma^k}\right]\cdot\sigma^k=
{1\over (i+j)!k!}\left[g_{y^iu^j\sigma^k}\right]\cdot\sigma^k$$ to
$g_{(yu)^{i+j}}$. In addition, note that the multiplier
$\left(\matrix{i+j\cr i}\right)$ is applied when the fully symmetric
tensor $[g_{(yu)^{i+j}}]$ is evaluated.
So we go through $i+j=d=0\ldots q$ and in each loop we form the fully
symmetric tensor $[g_{(yu)^l}]$ and insert it to the container.
@<|DecisionRuleImpl::fillTensors| code@>=
void fillTensors(const _Tg& g, double sigma)
{
IntSequence tns(2);
tns[0] = ypart.nys(); tns[1] = nu;
int dfact = 1;
for (int d = 0; d <= g.getMaxDim(); d++, dfact*=d) {
_Ttensym* g_yud = new _Ttensym(ypart.ny(), ypart.nys()+nu, d);
g_yud->zeros();
@<fill tensor of |g_yud| of dimension |d|@>;
this->insert(g_yud);
}
}
@ Here we have to fill the tensor $\left[g_{(yu)^d}\right]$. So we go
through all pairs $(i,j)$ giving $i+j=d$, and through all $k$ from
zero up to maximal dimension minus $d$. In this way we go through all
symmetries of $g_{y^iu^j\sigma^k}$ which will be added to $g_{(yu)^d}$.
Note that at the beginning, |dfact| is a factorial of |d|. We
calculate |kfact| is equal to $k!$. As indicated in
|@<|DecisionRuleImpl::fillTensors| code@>|, the added tensor is thus
multiplied with ${1\over d!k!}\sigma^k$.
@<fill tensor of |g_yud| of dimension |d|@>=
for (int i = 0; i <= d; i++) {
int j = d-i;
int kfact = 1;
_Ttensor tmp(ypart.ny(),
TensorDimens(Symmetry(i,j), tns));
tmp.zeros();
for (int k = 0; k+d <= g.getMaxDim(); k++, kfact*=k) {
Symmetry sym(i,j,0,k);
if (g.check(sym)) {
double mult = pow(sigma,k)/dfact/kfact;
tmp.add(mult,*(g.get(sym)));
}
}
g_yud->addSubTensor(tmp);
}
@ The centralization is straightforward. We suppose here that the
object's steady state is the fix point $\tilde y$. It is clear that
the new derivatives $\left[\tilde g_{(yu)^i}\right]$ will be equal to
the derivatives of the original decision rule |dr| at the new steady
state $\tilde y$. So, the new derivatives are obtained by derivating the
given decision rule $dr$ and evaluating its polynomial at
$$dstate=\left[\matrix{\tilde y^*-\bar y^*\cr 0}\right],$$
where $\bar y$ is the steady state of the original rule |dr|.
@<|DecisionRuleImpl::centralize| code@>=
void centralize(const DecisionRuleImpl& dr)
{
Vector dstate(ypart.nys() + nu);
dstate.zeros();
Vector dstate_star(dstate, 0, ypart.nys());
ConstVector newsteady_star(ysteady, ypart.nstat, ypart.nys());
ConstVector oldsteady_star(dr.ysteady, ypart.nstat, ypart.nys());
dstate_star.add(1.0, newsteady_star);
dstate_star.add(-1.0, oldsteady_star);
_Tpol pol(dr);
int dfac = 1;
for (int d = 1; d <= dr.getMaxDim(); d++, dfac *= d) {
pol.derivative(d-1);
_Ttensym* der = pol.evalPartially(d, dstate);
der->mult(1.0/dfac);
this->insert(der);
}
}
@ Here we evaluate repeatedly the polynomial storing results in the
created matrix. For exogenous shocks, we use |ShockRealization|
class, for predetermined variables, we use |ystart| as the first
state. The |ystart| vector is required to be all state variables
|ypart.ny()|, although only the predetermined part of |ystart| is
used.
We simulate in terms of $\Delta y$, this is, at the beginning the
|ysteady| is canceled from |ystart|, we simulate, and at the end
|ysteady| is added to all columns of the result.
@<|DecisionRuleImpl::simulate| code@>=
TwoDMatrix* simulate(emethod em, int np, const Vector& ystart,
ShockRealization& sr) const
{
KORD_RAISE_IF(ysteady.length() != ystart.length(),
"Start and steady lengths differ in DecisionRuleImpl::simulate");
TwoDMatrix* res = new TwoDMatrix(ypart.ny(), np);
@<initialize vectors and subvectors for simulation@>;
@<perform the first step of simulation@>;
@<perform all other steps of simulations@>;
@<add the steady state to columns of |res|@>;
return res;
}
@ Here allocate the stack vector $(\Delta y^*, u)$, define the
subvectors |dy|, and |u|, then we pickup predetermined parts of
|ystart| and |ysteady|.
@<initialize vectors and subvectors for simulation@>=
Vector dyu(ypart.nys()+nu);
ConstVector ystart_pred(ystart, ypart.nstat, ypart.nys());
ConstVector ysteady_pred(ysteady, ypart.nstat, ypart.nys());
Vector dy(dyu, 0, ypart.nys());
Vector u(dyu, ypart.nys(), nu);
@ We cancel |ysteady| from |ystart|, get realization to |u|, and
evaluate the polynomial.
@<perform the first step of simulation@>=
dy = ystart_pred;
dy.add(-1.0, ysteady_pred);
sr.get(0, u);
Vector out(*res, 0);
eval(em, out, dyu);
@ Also clear. If the result at some period is not finite, we pad the
rest of the matrix with zeros.
@<perform all other steps of simulations@>=
int i=1;
while (i < np) {
ConstVector ym(*res, i-1);
ConstVector dym(ym, ypart.nstat, ypart.nys());
dy = dym;
sr.get(i, u);
Vector out(*res, i);
eval(em, out, dyu);
if (! out.isFinite()) {
if (i+1 < np) {
TwoDMatrix rest(*res, i+1, np-i-1);
rest.zeros();
}
break;
}
i++;
}
@ Even clearer. We add the steady state to the numbers computed above
and leave the padded columns to zero.
@<add the steady state to columns of |res|@>=
for (int j = 0; j < i; j++) {
Vector col(*res, j);
col.add(1.0, ysteady);
}
@ This is one period evaluation of the decision rule. The simulation
is a sequence of repeated one period evaluations with a difference,
that the steady state (fix point) is cancelled and added once. Hence
we have two special methods.
@<|DecisionRuleImpl::evaluate| code@>=
void evaluate(emethod em, Vector& out, const ConstVector& ys,
const ConstVector& u) const
{
KORD_RAISE_IF(ys.length() != ypart.nys() || u.length() != nu,
"Wrong dimensions of input vectors in DecisionRuleImpl::evaluate");
KORD_RAISE_IF(out.length() != ypart.ny(),
"Wrong dimension of output vector in DecisionRuleImpl::evaluate");
ConstVector ysteady_pred(ysteady, ypart.nstat, ypart.nys());
Vector ys_u(ypart.nys()+nu);
Vector ys_u1(ys_u, 0, ypart.nys());
ys_u1 = ys;
ys_u1.add(-1.0, ysteady_pred);
Vector ys_u2(ys_u, ypart.nys(), nu);
ys_u2 = u;
eval(em, out, ys_u);
out.add(1.0, ysteady);
}
@ This is easy. We just return the newly created copy using the
centralized constructor.
@<|DecisionRuleImpl::centralizedClone| code@>=
DecisionRule* centralizedClone(const Vector& fixpoint) const
{
return new DecisionRuleImpl<t>(*this, fixpoint);
}
@ Here we only encapsulate two implementations to one, deciding
according to the parameter.
@<|DecisionRuleImpl::eval| code@>=
void eval(emethod em, Vector& out, const ConstVector& v) const
{
if (em == DecisionRule::horner)
_Tparent::evalHorner(out, v);
else
_Tparent::evalTrad(out, v);
}
@ Write the decision rule and steady state to the MAT file.
@<|DecisionRuleImpl::writeMat| code@>=
void writeMat(mat_t* fd, const char* prefix) const
{
ctraits<t>::Tpol::writeMat(fd, prefix);
TwoDMatrix dum(ysteady.length(), 1);
dum.getData() = ysteady;
char tmp[100];
sprintf(tmp, "%s_ss", prefix);
ConstTwoDMatrix(dum).writeMat(fd, tmp);
}
@ This is exactly the same as |DecisionRuleImpl<KOrder::fold>|. The
only difference is that we have a conversion from
|UnfoldDecisionRule|, which is exactly
|DecisionRuleImpl<KOrder::unfold>|.
@<|FoldDecisionRule| class declaration@>=
class UnfoldDecisionRule;
class FoldDecisionRule : public DecisionRuleImpl<KOrder::fold> {
friend class UnfoldDecisionRule;
public:@;
FoldDecisionRule(const ctraits<KOrder::fold>::Tpol& pol, const PartitionY& yp, int nuu,
const Vector& ys)
: DecisionRuleImpl<KOrder::fold>(pol, yp, nuu, ys) {}
FoldDecisionRule(ctraits<KOrder::fold>::Tpol& pol, const PartitionY& yp, int nuu,
const Vector& ys)
: DecisionRuleImpl<KOrder::fold>(pol, yp, nuu, ys) {}
FoldDecisionRule(const ctraits<KOrder::fold>::Tg& g, const PartitionY& yp, int nuu,
const Vector& ys, double sigma)
: DecisionRuleImpl<KOrder::fold>(g, yp, nuu, ys, sigma) {}
FoldDecisionRule(const DecisionRuleImpl<KOrder::fold>& dr, const ConstVector& fixpoint)
: DecisionRuleImpl<KOrder::fold>(dr, fixpoint) {}
FoldDecisionRule(const UnfoldDecisionRule& udr);
};
@ This is exactly the same as |DecisionRuleImpl<KOrder::unfold>|, but
with a conversion from |FoldDecisionRule|, which is exactly
|DecisionRuleImpl<KOrder::fold>|.
@<|UnfoldDecisionRule| class declaration@>=
class UnfoldDecisionRule : public DecisionRuleImpl<KOrder::unfold> {
friend class FoldDecisionRule;
public:@;
UnfoldDecisionRule(const ctraits<KOrder::unfold>::Tpol& pol, const PartitionY& yp, int nuu,
const Vector& ys)
: DecisionRuleImpl<KOrder::unfold>(pol, yp, nuu, ys) {}
UnfoldDecisionRule(ctraits<KOrder::unfold>::Tpol& pol, const PartitionY& yp, int nuu,
const Vector& ys)
: DecisionRuleImpl<KOrder::unfold>(pol, yp, nuu, ys) {}
UnfoldDecisionRule(const ctraits<KOrder::unfold>::Tg& g, const PartitionY& yp, int nuu,
const Vector& ys, double sigma)
: DecisionRuleImpl<KOrder::unfold>(g, yp, nuu, ys, sigma) {}
UnfoldDecisionRule(const DecisionRuleImpl<KOrder::unfold>& dr, const ConstVector& fixpoint)
: DecisionRuleImpl<KOrder::unfold>(dr, fixpoint) {}
UnfoldDecisionRule(const FoldDecisionRule& udr);
};
@ This class serves for calculation of the fix point of the decision
rule given that the shocks are zero. The class is very similar to the
|DecisionRuleImpl|. Besides the calculation of the fix point, the only
difference between |DRFixPoint| and |DecisionRuleImpl| is that the
derivatives wrt. shocks are ignored (since shocks are zero during the
calculations). That is why have a different |fillTensor| method.
The solution algorithm is Newton and is described in
|@<|DRFixPoint::solveNewton| code@>|. It solves $F(y)=0$, where
$F=g(y,0)-y$. The function $F$ is given by its derivatives |bigf|. The
Jacobian of the solved system is given by derivatives stored in
|bigfder|.
@<|DRFixPoint| class declaration@>=
template <int t>
class DRFixPoint : public ctraits<t>::Tpol {
typedef typename ctraits<t>::Tpol _Tparent;
static int max_iter;
static int max_newton_iter;
static int newton_pause;
static double tol;
const Vector ysteady;
const PartitionY ypart;
_Tparent* bigf;
_Tparent* bigfder;
public:@;
typedef typename DecisionRule::emethod emethod;
@<|DRFixPoint| constructor code@>;
@<|DRFixPoint| destructor code@>;
@<|DRFixPoint::calcFixPoint| code@>;
int getNumIter() const
{@+ return iter;@+}
int getNewtonLastIter() const
{@+ return newton_iter_last;@+}
int getNewtonTotalIter() const
{@+ return newton_iter_total;@+}
protected:@;
@<|DRFixPoint::fillTensors| code@>;
@<|DRFixPoint::solveNewton| code@>;
private:@;
int iter;
int newton_iter_last;
int newton_iter_total;
};
@ Here we have to setup the function $F=g(y,0)-y$ and ${\partial
F\over\partial y}$. The former is taken from the given derivatives of
$g$ where a unit matrix is subtracted from the first derivative
(|Symmetry(1)|). Then the derivative of the $F$ polynomial is
calculated.
@<|DRFixPoint| constructor code@>=
DRFixPoint(const _Tg& g, const PartitionY& yp,
const Vector& ys, double sigma)
: ctraits<t>::Tpol(yp.ny(), yp.nys()),
ysteady(ys), ypart(yp), bigf(NULL), bigfder(NULL)
{
fillTensors(g, sigma);
_Tparent yspol(ypart.nstat, ypart.nys(), *this);
bigf = new _Tparent((const _Tparent&) yspol);
_Ttensym* frst = bigf->get(Symmetry(1));
for (int i = 0; i < ypart.nys(); i++)
frst->get(i,i) = frst->get(i,i) - 1;
bigfder = new _Tparent(*bigf, 0);
}
@
@<|DRFixPoint| destructor code@>=
virtual ~DRFixPoint()
{
if (bigf)
delete bigf;
if (bigfder)
delete bigfder;
}
@ Here we fill the tensors for the |DRFixPoint| class. We ignore the
derivatives $g_{y^iu^j\sigma^k}$ for which $j>0$. So we go through all
dimensions |d|, and all |k| such that |d+k| is between the maximum
dimension and |d|, and add ${\sigma^k\over d!k!}g_{y^d\sigma^k}$ to
the tensor $g_{(y)^d}$.
@<|DRFixPoint::fillTensors| code@>=
void fillTensors(const _Tg& g, double sigma)
{
int dfact = 1;
for (int d = 0; d <= g.getMaxDim(); d++, dfact*=d) {
_Ttensym* g_yd = new _Ttensym(ypart.ny(), ypart.nys(), d);
g_yd->zeros();
int kfact = 1;
for (int k = 0; d+k <= g.getMaxDim(); k++, kfact*=k) {
if (g.check(Symmetry(d,0,0,k))) {
const _Ttensor* ten = g.get(Symmetry(d,0,0,k));
double mult = pow(sigma,k)/dfact/kfact;
g_yd->add(mult, *ten);
}
}
this->insert(g_yd);
}
}
@ This tries to solve polynomial equation $F(y)=0$, where $F$
polynomial is |bigf| and its derivative is in |bigfder|. It returns
true if the Newton converged. The method takes the given vector as
initial guess, and rewrites it with a solution. The method guarantees
to return the vector, which has smaller norm of the residual. That is
why the input/output vector |y| is always changed.
The method proceeds with a Newton step, if the Newton step improves
the residual error. So we track residual errors in |flastnorm| and
|fnorm| (former and current). In addition, at each step we search for
an underrelaxation parameter |urelax|, which improves the residual. If
|urelax| is less that |urelax_threshold|, we stop searching and stop
the Newton.
@<|DRFixPoint::solveNewton| code@>=
bool solveNewton(Vector& y)
{
const double urelax_threshold = 1.e-5;
Vector sol((const Vector&) y);
Vector delta(y.length());
newton_iter_last = 0;
bool delta_finite = true;
double flastnorm = 0.0;
double fnorm = 0.0;
bool converged = false;
double urelax = 1.0;
do {
_Ttensym* jacob = bigfder->evalPartially(1, sol);
bigf->evalHorner(delta, sol);
if (newton_iter_last == 0)
flastnorm = delta.getNorm();
delta_finite = delta.isFinite();
if (delta_finite) {
ConstTwoDMatrix(*jacob).multInvLeft(delta);
@<find |urelax| improving residual@>;
sol.add(-urelax, delta);
delta_finite = delta.isFinite();
}
delete jacob;
newton_iter_last++;
converged = delta_finite && fnorm < tol;
flastnorm = fnorm;
} while (!converged && newton_iter_last < max_newton_iter
&& urelax > urelax_threshold);
newton_iter_total += newton_iter_last;
if (! converged)
newton_iter_last = 0;
y = (const Vector&)sol;
return converged;
}
@ Here we find the |urelax|. We cycle as long as the new residual size
|fnorm| is greater than last residual size |flastnorm|. If the urelax
is less than |urelax_threshold| we give up. The |urelax| is damped by
the ratio of |flastnorm| and |fnorm|. It the ratio is close to one, we
damp by one half.
@<find |urelax| improving residual@>=
bool urelax_found = false;
urelax = 1.0;
while (!urelax_found && urelax > urelax_threshold) {
Vector soltmp((const Vector&)sol);
soltmp.add(-urelax, delta);
Vector f(sol.length());
bigf->evalHorner(f, soltmp);
fnorm = f.getNorm();
if (fnorm <= flastnorm)
urelax_found = true;
else
urelax *= std::min(0.5, flastnorm/fnorm);
}
@ This method solves the fix point of the no-shocks rule
$y_{t+1}=f(y_t)$. It combines dull steps with Newton attempts. The
dull steps correspond to evaluations setting $y_{t+1}=f(y_t)$. For
reasonable models the dull steps converge to the fix-point but very
slowly. That is why we make Newton attempt from time to time. The
frequency of the Newton attempts is given by |newton_pause|. We
perform the calculations in deviations from the steady state. So, at
the end, we have to add the steady state.
The method also sets the members |iter|, |newton_iter_last| and
|newton_iter_total|. These numbers can be examined later.
The |out| vector is not touched if the algorithm has not convered.
@<|DRFixPoint::calcFixPoint| code@>=
bool calcFixPoint(emethod em, Vector& out)
{
KORD_RAISE_IF(out.length() != ypart.ny(),
"Wrong length of out in DRFixPoint::calcFixPoint");
Vector delta(ypart.nys());
Vector ystar(ypart.nys());
ystar.zeros();
iter = 0;
newton_iter_last = 0;
newton_iter_total = 0;
bool converged = false;
do {
if ((iter/newton_pause)*newton_pause == iter)
converged = solveNewton(ystar);
if (! converged) {
bigf->evalHorner(delta, ystar);
KORD_RAISE_IF_X(! delta.isFinite(),
"NaN or Inf asserted in DRFixPoint::calcFixPoint",
KORD_FP_NOT_FINITE);
ystar.add(1.0, delta);
converged = delta.getNorm() < tol;
}
iter++;
} while (iter < max_iter && ! converged);
if (converged) {
_Tparent::evalHorner(out, ystar);
out.add(1.0, ysteady);
}
return converged;
}
@ This is a basically a number of matrices of the same dimensions,
which can be obtained as simulation results from a given decision rule
and shock realizations. We also store the realizations of shocks.
@<|SimResults| class declaration@>=
class ExplicitShockRealization;
class SimResults {
protected:@;
int num_y;
int num_per;
int num_burn;
vector<TwoDMatrix*> data;
vector<ExplicitShockRealization*> shocks;
public:@;
SimResults(int ny, int nper, int nburn = 0)
: num_y(ny), num_per(nper), num_burn(nburn)@+ {}
virtual ~SimResults();
void simulate(int num_sim, const DecisionRule& dr, const Vector& start,
const TwoDMatrix& vcov, Journal& journal);
void simulate(int num_sim, const DecisionRule& dr, const Vector& start,
const TwoDMatrix& vcov);
int getNumPer() const
{@+ return num_per;@+}
int getNumBurn() const
{@+ return num_burn;@+}
int getNumSets() const
{@+ return (int)data.size();@+}
const TwoDMatrix& getData(int i) const
{@+ return *(data[i]);@+}
const ExplicitShockRealization& getShocks(int i) const
{ @+ return *(shocks[i]);@+}
bool addDataSet(TwoDMatrix* d, ExplicitShockRealization* sr);
void writeMat(const char* base, const char* lname) const;
void writeMat(mat_t* fd, const char* lname) const;
};
@ This does the same as |SimResults| plus it calculates means and
covariances of the simulated data.
@<|SimResultsStats| class declaration@>=
class SimResultsStats : public SimResults {
protected:@;
Vector mean;
TwoDMatrix vcov;
public:@;
SimResultsStats(int ny, int nper, int nburn = 0)
: SimResults(ny, nper, nburn), mean(ny), vcov(ny,ny)@+ {}
void simulate(int num_sim, const DecisionRule& dr, const Vector& start,
const TwoDMatrix& vcov, Journal& journal);
void writeMat(mat_t* fd, const char* lname) const;
protected:@;
void calcMean();
void calcVcov();
};
@ This does the similar thing as |SimResultsStats| but the statistics are
not calculated over all periods but only within each period. Then we
do not calculate covariances with periods but only variances.
@<|SimResultsDynamicStats| class declaration@>=
class SimResultsDynamicStats : public SimResults {
protected:@;
TwoDMatrix mean;
TwoDMatrix variance;
public:@;
SimResultsDynamicStats(int ny, int nper, int nburn = 0)
: SimResults(ny, nper, nburn), mean(ny,nper), variance(ny,nper)@+ {}
void simulate(int num_sim, const DecisionRule& dr, const Vector& start,
const TwoDMatrix& vcov, Journal& journal);
void writeMat(mat_t* fd, const char* lname) const;
protected:@;
void calcMean();
void calcVariance();
};
@ This goes through control simulation results, and for each control
it adds a given impulse to a given shock and runs a simulation. The
control simulation is then cancelled and the result is stored. After
that these results are averaged with variances calculated.
The means and the variances are then written to the MAT-4 file.
@<|SimResultsIRF| class declaration@>=
class SimulationIRFWorker;
class SimResultsIRF : public SimResults {
friend class SimulationIRFWorker;
protected:@;
const SimResults& control;
int ishock;
double imp;
TwoDMatrix means;
TwoDMatrix variances;
public:@;
SimResultsIRF(const SimResults& cntl, int ny, int nper, int i, double impulse)
: SimResults(ny, nper, 0), control(cntl),
ishock(i), imp(impulse),
means(ny, nper), variances(ny, nper)@+ {}
void simulate(const DecisionRule& dr, Journal& journal);
void simulate(const DecisionRule& dr);
void writeMat(mat_t* fd, const char* lname) const;
protected:@;
void calcMeans();
void calcVariances();
};
@ This simulates and gathers all statistics from the real time
simulations. In the |simulate| method, it runs |RTSimulationWorker|s
which accummulate information from their own estimates. The estimation
is done by means of |NormalConj| class, which is a conjugate family of
densities for normal distibutions.
@<|RTSimResultsStats| class declaration@>=
class RTSimulationWorker;
class RTSimResultsStats {
friend class RTSimulationWorker;
protected:@;
Vector mean;
TwoDMatrix vcov;
int num_per;
int num_burn;
NormalConj nc;
int incomplete_simulations;
int thrown_periods;
public:@;
RTSimResultsStats(int ny, int nper, int nburn = 0)
: mean(ny), vcov(ny, ny),
num_per(nper), num_burn(nburn), nc(ny),
incomplete_simulations(0), thrown_periods(0)@+ {}
void simulate(int num_sim, const DecisionRule& dr, const Vector& start,
const TwoDMatrix& vcov, Journal& journal);
void simulate(int num_sim, const DecisionRule& dr, const Vector& start,
const TwoDMatrix& vcov);
void writeMat(mat_t* fd, const char* lname);
};
@ For each shock, this simulates plus and minus impulse. The class
maintains a vector of simulation results, each gets a particular shock
and sign (positive/negative). The results of type |SimResultsIRF| are
stored in a vector so that even ones are positive, odd ones are
negative.
The constructor takes a reference to the control simulations, which
must be finished before the constructor is called. The control
simulations are passed to all |SimResultsIRF|s.
The constructor also takes the vector of indices of exogenous
variables (|ili|) for which the IRFs are generated. The list is kept
(as |irf_list_ind|) for other methods.
@<|IRFResults| class declaration@>=
class DynamicModel;
class IRFResults {
vector<SimResultsIRF*> irf_res;
const DynamicModel& model;
vector<int> irf_list_ind;
public:@;
IRFResults(const DynamicModel& mod, const DecisionRule& dr,
const SimResults& control, const vector<int>& ili,
Journal& journal);
~IRFResults();
void writeMat(mat_t* fd, const char* prefix) const;
};
@ This worker simulates the given decision rule and inserts the result
to |SimResults|.
@<|SimulationWorker| class declaration@>=
class SimulationWorker : public THREAD {
protected:@;
SimResults& res;
const DecisionRule& dr;
DecisionRule::emethod em;
int np;
const Vector& st;
ShockRealization& sr;
public:@;
SimulationWorker(SimResults& sim_res,
const DecisionRule& dec_rule,
DecisionRule::emethod emet, int num_per,
const Vector& start, ShockRealization& shock_r)
: res(sim_res), dr(dec_rule), em(emet), np(num_per), st(start), sr(shock_r) {}
void operator()();
};
@ This worker simulates a given impulse |imp| to a given shock
|ishock| based on a given control simulation with index |idata|. The
control simulations are contained in |SimResultsIRF| which is passed
to the constructor.
@<|SimulationIRFWorker| class declaration@>=
class SimulationIRFWorker : public THREAD {
SimResultsIRF& res;
const DecisionRule& dr;
DecisionRule::emethod em;
int np;
int idata;
int ishock;
double imp;
public:@;
SimulationIRFWorker(SimResultsIRF& sim_res,
const DecisionRule& dec_rule,
DecisionRule::emethod emet, int num_per,
int id, int ishck, double impulse)
: res(sim_res), dr(dec_rule), em(emet), np(num_per),
idata(id), ishock(ishck), imp(impulse)@+ {}
void operator()();
};
@ This class does the real time simulation job for
|RTSimResultsStats|. It simulates the model period by period. It
accummulates the information in the |RTSimResultsStats::nc|. If NaN or
Inf is observed, it ends the simulation and adds to the
|thrown_periods| of |RTSimResultsStats|.
@<|RTSimulationWorker| class declaration@>=
class RTSimulationWorker : public THREAD {
protected:@;
RTSimResultsStats& res;
const DecisionRule& dr;
DecisionRule::emethod em;
int np;
const Vector& ystart;
ShockRealization& sr;
public:@;
RTSimulationWorker(RTSimResultsStats& sim_res,
const DecisionRule& dec_rule,
DecisionRule::emethod emet, int num_per,
const Vector& start, ShockRealization& shock_r)
: res(sim_res), dr(dec_rule), em(emet), np(num_per), ystart(start), sr(shock_r) {}
void operator()();
};
@ This class generates draws from Gaussian distribution with zero mean
and the given variance-covariance matrix. It stores the factor of vcov
$V$ matrix, yielding $FF^T = V$.
@<|RandomShockRealization| class declaration@>=
class RandomShockRealization : virtual public ShockRealization {
protected:@;
MersenneTwister mtwister;
TwoDMatrix factor;
public:@;
RandomShockRealization(const TwoDMatrix& v, unsigned int iseed)
: mtwister(iseed), factor(v.nrows(),v.nrows())
{@+schurFactor(v);@+}
RandomShockRealization(const RandomShockRealization& sr)
: mtwister(sr.mtwister), factor(sr.factor)@+ {}
virtual ~RandomShockRealization() @+{}
void get(int n, Vector& out);
int numShocks() const
{@+ return factor.nrows();@+}
protected:@;
void choleskyFactor(const TwoDMatrix& v);
void schurFactor(const TwoDMatrix& v);
};
@ This is just a matrix of finite numbers. It can be constructed from
any |ShockRealization| with a given number of periods.
@<|ExplicitShockRealization| class declaration@>=
class ExplicitShockRealization : virtual public ShockRealization {
TwoDMatrix shocks;
public:@;
ExplicitShockRealization(const TwoDMatrix& sh)
: shocks(sh)@+ {}
ExplicitShockRealization(const ConstTwoDMatrix& sh)
: shocks(sh)@+ {}
ExplicitShockRealization(const ExplicitShockRealization& sr)
: shocks(sr.shocks)@+ {}
ExplicitShockRealization(ShockRealization& sr, int num_per);
void get(int n, Vector& out);
int numShocks() const
{@+ return shocks.nrows();@+}
const TwoDMatrix& getShocks()
{@+ return shocks;@+}
void addToShock(int ishock, int iper, double val);
void print() const
{@+ shocks.print();@+}
};
@ This represents a user given shock realization. The first matrix of
the constructor is a covariance matrix of shocks, the second matrix is
a rectangular matrix, where columns correspond to periods, rows to
shocks. If an element of the matrix is {\tt NaN}, or {\tt Inf}, or
{\tt -Inf}, then the random shock is taken instead of that element.
In this way it is a generalization of both |RandomShockRealization|
and |ExplicitShockRealization|.
@<|GenShockRealization| class declaration@>=
class GenShockRealization : public RandomShockRealization, public ExplicitShockRealization {
public:@;
GenShockRealization(const TwoDMatrix& v, const TwoDMatrix& sh, int seed)
: RandomShockRealization(v, seed), ExplicitShockRealization(sh)@+
{
KORD_RAISE_IF(sh.nrows() != v.nrows() || v.nrows() != v.ncols(),
"Wrong dimension of input matrix in GenShockRealization constructor");
}
void get(int n, Vector& out);
int numShocks() const
{@+ return RandomShockRealization::numShocks();@+}
};
@ End of {\tt decision\_rule.h} file.

View File

View File

@ -0,0 +1,72 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
#include "dynamic_model.hh"
#include <iostream>
#include <algorithm>
void
NameList::print() const
{
for (int i = 0; i < getNum(); i++)
std::cout << getName(i) << '\n';
}
void
NameList::writeMat(mat_t *fd, const std::string &vname) const
{
int maxlen = 0;
for (int i = 0; i < getNum(); i++)
maxlen = std::max(maxlen, static_cast<int>(getName(i).size()));
if (maxlen == 0)
return;
auto m = std::make_unique<char[]>(getNum()*maxlen);
for (int i = 0; i < getNum(); i++)
for (int j = 0; j < maxlen; j++)
if (j < static_cast<int>(getName(i).size()))
m[j*getNum()+i] = getName(i)[j];
else
m[j*getNum()+i] = ' ';
size_t dims[2];
dims[0] = getNum();
dims[1] = maxlen;
matvar_t *v = Mat_VarCreate(vname.c_str(), MAT_C_CHAR, MAT_T_UINT8, 2, dims, m.get(), 0);
Mat_VarWrite(fd, v, MAT_COMPRESSION_NONE);
Mat_VarFree(v);
}
void
NameList::writeMatIndices(mat_t *fd, const std::string &prefix) const
{
TwoDMatrix aux(1, 1);
for (int i = 0; i < getNum(); i++)
{
aux.get(0, 0) = i+1;
aux.writeMat(fd, prefix + "_i_" + getName(i));
}
}

View File

@ -1,73 +0,0 @@
@q $Id: dynamic_model.cweb 431 2005-08-16 15:41:01Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@ Start of {\tt dynamic\_model.cpp} file.
@c
#include "dynamic_model.h"
@<|NameList::print| code@>;
@<|NameList::writeMat| code@>;
@<|NameList::writeMatIndices| code@>;
@
@<|NameList::print| code@>=
void NameList::print() const
{
for (int i = 0; i < getNum(); i++)
printf("%s\n", getName(i));
}
@
@<|NameList::writeMat| code@>=
void NameList::writeMat(mat_t* fd, const char* vname) const
{
int maxlen = 0;
for (int i = 0; i < getNum(); i++)
if (maxlen < (int)strlen(getName(i)))
maxlen = (int)strlen(getName(i));
if (maxlen == 0)
return;
char *m = new char[getNum()*maxlen];
for (int i = 0; i < getNum(); i++)
for (int j = 0; j < maxlen; j++)
if (j < (int)strlen(getName(i)))
m[j*getNum()+i] = getName(i)[j];
else
m[j*getNum()+i] = ' ';
# if MATIO_MAJOR_VERSION > 1 || (MATIO_MAJOR_VERSION == 1 && MATIO_MINOR_VERSION >= 5)
size_t dims[2];
const matio_compression compression = MAT_COMPRESSION_NONE;
# else
int dims[2];
const int compression = COMPRESSION_NONE;
# endif
dims[0] = getNum();
dims[1] = maxlen;
matvar_t *v = Mat_VarCreate(vname, MAT_C_CHAR, MAT_T_UINT8, 2, dims, m, 0);
Mat_VarWrite(fd, v, compression);
Mat_VarFree(v);
delete[] m;
}
@
@<|NameList::writeMatIndices| code@>=
void NameList::writeMatIndices(mat_t* fd, const char* prefix) const
{
char tmp[100];
TwoDMatrix aux(1,1);
for (int i = 0; i < getNum(); i++) {
sprintf(tmp, "%s_i_%s", prefix, getName(i));
aux.get(0,0) = i+1;
aux.writeMat(fd, tmp);
}
}
@ End of {\tt dynamic\_model.cpp} file.

View File

@ -0,0 +1,145 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
// Dynamic model abstraction
/* This file only defines a generic interface to a DSGE model. The model
takes the form:
𝔼(f(g**(g*(y,u),u),g(y,u),y,u)) = 0
The interface is defined via pure virtual class DynamicModel. */
#ifndef DYNAMIC_MODEL_H
#define DYNAMIC_MODEL_H
#include "t_container.hh"
#include "sparse_tensor.hh"
#include "Vector.hh"
#include <memory>
#include <string>
/* The class is a virtual pure class which provides an access to names
of the variables. */
class NameList
{
public:
virtual ~NameList() = default;
virtual int getNum() const = 0;
virtual const std::string &getName(int i) const = 0;
void print() const;
void writeMat(mat_t *fd, const std::string &vname) const;
void writeMatIndices(mat_t *fd, const std::string &prefix) const;
};
/* This is the interface to an information on a generic DSGE model. It is
sufficient for calculations of policy rule Taylor approximations at some
(not necessarily deterministic) steady state.
We need to know a partitioning of endogenous variables y. We suppose that y
is partitioned as:
static
pred
y = both
forward
of which we define:
pred both
y* = both y** = forward
where static are meant those variables, which appear only at time t;
pred are meant those variables, which appear only at t and t1; both are
meant those variables, which appear at least at t1 and t+1; and forward
are meant those variables, which appear only at t and t+1. This partitioning
is given by methods nstat(), npred(), nboth(), and nforw(). The number of
equations numeq() must be the same as a number of endogenous variables.
In order to complete description, we need to know a number of exogenous
variables, which is a size of u, hence nexog() method.
The model contains an information about names of variables, the
variance-covariance matrix of the shocks, the derivatives of equations of f
at some steady state, and the steady state. These can be retrieved by the
corresponding methods.
The derivatives of the system are calculated with respect to stacked
variables, the stack looks like:
y**
y
y*
u
There are only three operations. The first solveDeterministicSteady() solves
the deterministic steady steate which can be retrieved by getSteady() later.
The method evaluateSystem() calculates f(y**,y,y*,u), where y and u are
passed, or f(y**, y, y*, u), where y**, y, y*, u are passed.
Finally, the method calcDerivativesAtSteady() calculates derivatives of f at
the current steady state, and zero shocks. The derivatives can be retrieved
with getModelDerivatives(). All the derivatives are done up to a given order
in the model, which can be retrieved by order().
The model initialization is done in a constructor of the implementing class.
The constructor usually calls a parser, which parses a given file (usually a
text file), and retrieves all necessary information about the model,
inluding variables, partitioning, variance-covariance matrix, information
helpful for calculation of the deterministic steady state, and so on. */
class DynamicModel
{
public:
virtual std::unique_ptr<DynamicModel> clone() const = 0;
virtual ~DynamicModel() = default;
virtual int nstat() const = 0;
virtual int nboth() const = 0;
virtual int npred() const = 0;
virtual int nforw() const = 0;
virtual int nexog() const = 0;
virtual int order() const = 0;
int
numeq() const
{
return nstat()+nboth()+npred()+nforw();
}
virtual const NameList &getAllEndoNames() const = 0;
virtual const NameList &getStateNames() const = 0;
virtual const NameList &getExogNames() const = 0;
virtual const TwoDMatrix &getVcov() const = 0;
virtual const TensorContainer<FSSparseTensor> &getModelDerivatives() const = 0;
virtual const Vector &getSteady() const = 0;
virtual Vector &getSteady() = 0;
virtual void solveDeterministicSteady() = 0;
virtual void evaluateSystem(Vector &out, const ConstVector &yy, const Vector &xx) = 0;
virtual void evaluateSystem(Vector &out, const ConstVector &yym, const ConstVector &yy,
const ConstVector &yyp, const Vector &xx) = 0;
virtual void calcDerivativesAtSteady() = 0;
};
#endif

View File

@ -1,120 +0,0 @@
@q $Id: dynamic_model.hweb 378 2005-07-21 15:50:20Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@*2 Dynamic model abstraction. Start of {\tt dynamic\_model.h} file.
This file only defines a generic interface to an SDGE model. The model
takes the form:
$$E_t\left[f(g^{**}(g^*(y,u_t),u_{t+1}),g(y,u),y,u_t)\right]=0$$
The interface is defined via pure virtual class |DynamicModel|.
@s NameList int
@s DynamicModel int
@c
#ifndef DYNAMIC_MODEL_H
#define DYNAMIC_MODEL_H
#include "t_container.h"
#include "sparse_tensor.h"
#include "Vector.h"
@<|NameList| class declaration@>;
@<|DynamicModel| class declaration@>;
#endif
@ The class is a virtual pure class which provides an access to names
of the variables.
@<|NameList| class declaration@>=
class NameList {
public:@;
virtual ~NameList() {}
virtual int getNum() const =0;
virtual const char* getName(int i) const=0;
void print() const;
void writeMat(mat_t* fd, const char* vname) const;
void writeMatIndices(mat_t* fd, const char* prefix) const;
};
@ This is the interface to an information on a generic SDGE
model. It is sufficient for calculations of policy rule Taylor
approximations at some (not necessarily deterministic) steady state.
We need to know a partitioning of endogenous variables $y$. We suppose
that $y$ is partitioned as
$$y=\left[\matrix{\hbox{static}\cr\hbox{pred}\cr\hbox{both}\cr\hbox{forward}}\right]$$
of which we define
$$y^*=\left[\matrix{\hbox{pred}\cr\hbox{both}}\right]\quad
y^{**}=\left[\matrix{\hbox{both}\cr\hbox{forward}}\right]$$
where ``static'' are meant those variables, which appear only at time
$t$; ``pred'' are meant those variables, which appear only at $t$ and
$t-1$; ``both'' are meant those variables, which appear at least at
$t-1$ and $t+1$; and ``forward'' are meant those variables, which
appear only at $t$ and $t+1$. This partitioning is given by methods
|nstat()|, |npred()|, |nboth()|, and |nforw()|. The number of
equations |numeq()| must be the same as a number of endogenous
variables.
In order to complete description, we need to know a number of
exogenous variables, which is a size of $u$, hence |nexog()| method.
The model contains an information about names of variables, the
variance-covariance matrix of the shocks, the derivatives of equations
of $f$ at some steady state, and the steady state. These can be
retrieved by the corresponding methods.
The derivatives of the system are calculated with respect to stacked
variables, the stack looks as:
$$\left[\matrix{y^{**}_{t+1}\cr y_t\cr y^*_{t-1}\cr u_t}\right].$$
There are only three operations. The first
|solveDeterministicSteady()| solves the deterministic steady steate
which can be retrieved by |getSteady()| later. The method
|evaluateSystem| calculates $f(y^{**},y,y^*,u)$, where $y$ and $u$ are
passed, or $f(y^{**}_{t+1}, y_t, y^*_{t-1}, u)$, where $y^{**}_{t+1}$,
$y_t$, $y^*_{t-1}$, $u$ are passed. Finally, the method
|calcDerivativesAtSteady()| calculates derivatives of $f$ at the
current steady state, and zero shocks. The derivatives can be
retrieved with |getModelDerivatives()|. All the derivatives are done
up to a given order in the model, which can be retrieved by |order()|.
The model initialization is done in a constructor of the implementing
class. The constructor usually calls a parser, which parses a given
file (usually a text file), and retrieves all necessary information
about the model, inluding variables, partitioning, variance-covariance
matrix, information helpful for calculation of the deterministic
steady state, and so on.
@<|DynamicModel| class declaration@>=
class DynamicModel {
public:@;
virtual DynamicModel* clone() const =0;
virtual ~DynamicModel() {}
virtual int nstat() const =0;
virtual int nboth() const =0;
virtual int npred() const =0;
virtual int nforw() const =0;
virtual int nexog() const =0;
virtual int order() const =0;
int numeq() const
{@+ return nstat()+nboth()+npred()+nforw(); @+}
virtual const NameList& getAllEndoNames() const =0;
virtual const NameList& getStateNames() const =0;
virtual const NameList& getExogNames() const =0;
virtual const TwoDMatrix& getVcov() const =0;
virtual const TensorContainer<FSSparseTensor>& getModelDerivatives() const =0;
virtual const Vector& getSteady() const =0;
virtual Vector& getSteady() =0;
virtual void solveDeterministicSteady() =0;
virtual void evaluateSystem(Vector& out, const Vector& yy, const Vector& xx) =0;
virtual void evaluateSystem(Vector& out, const Vector& yym, const Vector& yy,
const Vector& yyp, const Vector& xx) =0;
virtual void calcDerivativesAtSteady() =0;
};
@ End of {\tt dynamic\_model.h} file.

View File

@ -0,0 +1,161 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
#include "faa_di_bruno.hh"
#include "fine_container.hh"
#include <cmath>
// FaaDiBruno::calculate() folded sparse code
/* We take an opportunity to refine the stack container to avoid allocation of
more memory than available. */
void
FaaDiBruno::calculate(const StackContainer<FGSTensor> &cont,
const TensorContainer<FSSparseTensor> &f,
FGSTensor &out)
{
out.zeros();
for (int l = 1; l <= out.dimen(); l++)
{
auto [max, mem_mb, p_size_mb] = estimRefinement(out.getDims(), out.nrows(), l);
FoldedFineContainer fine_cont(cont, max);
fine_cont.multAndAdd(l, f, out);
JournalRecord recc(journal);
recc << "dim=" << l << " avmem=" << mem_mb << " tmpmem=" << p_size_mb << " max=" << max
<< " stacks=" << cont.numStacks() << u8"" << fine_cont.numStacks() << endrec;
}
}
// FaaDiBruno::calculate() folded dense code
/* Here we just simply evaluate multAndAdd() for the dense container. There is
no opportunity for tuning. */
void
FaaDiBruno::calculate(const FoldedStackContainer &cont, const FGSContainer &g,
FGSTensor &out)
{
out.zeros();
for (int l = 1; l <= out.dimen(); l++)
{
long int mem = SystemResources::availableMemory();
cont.multAndAdd(l, g, out);
JournalRecord rec(journal);
int mem_mb = mem/1024/1024;
rec << "dim=" << l << " avmem=" << mem_mb << endrec;
}
}
// FaaDiBruno::calculate() unfolded sparse code
/* This is the same as FaaDiBruno::calculate() folded sparse code. The only
difference is that we construct unfolded fine container. */
void
FaaDiBruno::calculate(const StackContainer<UGSTensor> &cont,
const TensorContainer<FSSparseTensor> &f,
UGSTensor &out)
{
out.zeros();
for (int l = 1; l <= out.dimen(); l++)
{
auto [max, mem_mb, p_size_mb] = estimRefinement(out.getDims(), out.nrows(), l);
UnfoldedFineContainer fine_cont(cont, max);
fine_cont.multAndAdd(l, f, out);
JournalRecord recc(journal);
recc << "dim=" << l << " avmem=" << mem_mb << " tmpmem=" << p_size_mb << " max=" << max
<< " stacks=" << cont.numStacks() << u8"" << fine_cont.numStacks() << endrec;
}
}
// FaaDiBruno::calculate() unfolded dense code
/* Again, no tuning opportunity here. */
void
FaaDiBruno::calculate(const UnfoldedStackContainer &cont, const UGSContainer &g,
UGSTensor &out)
{
out.zeros();
for (int l = 1; l <= out.dimen(); l++)
{
long int mem = SystemResources::availableMemory();
cont.multAndAdd(l, g, out);
JournalRecord rec(journal);
int mem_mb = mem/1024/1024;
rec << "dim=" << l << " avmem=" << mem_mb << endrec;
}
}
/* This function returns a number of maximum rows used for refinement of the
stacked container. We want to set the maximum so that the expected memory
consumption for the number of paralel threads would be less than available
memory. On the other hand we do not want to be too pesimistic since a very
fine refinement can be very slow.
Besides memory needed for a dense unfolded slice of a tensor from f, each
thread needs magic_mult*per_size bytes of memory. In the worst case,
magic_mult will be equal to 2, this means memory per_size for target
temporary (permuted symmetry) tensor plus one copy for intermediate result.
However, this shows to be too pesimistic, so we set magic_mult to 1.5. The
memory for permuted symmetry temporary tensor per_size is estimated as a
weigthed average of unfolded memory of the out tensor and unfolded memory
of a symetric tensor with the largest coordinate size. Some experiments
showed that the best combination of the two is to take 100% if the latter,
so we set lambda to zero.
The max number of rows in the refined cont must be such that each
slice fits to remaining memory. Number of columns of the slice are
never greater maxˡ. (This is not true, since stacks corresponding to
unit/zero matrices cannot be further refined). We get an equation:
nthreads·maxˡ·8·r = mem magic_mult·nthreads·per_size·8·r
where mem is available memory in bytes, nthreads is a number of threads,
r is a number of rows, and 8 is sizeof(double).
If the right hand side is less than zero, we set max to 10, just to let it
do something. */
std::tuple<int, int, int>
FaaDiBruno::estimRefinement(const TensorDimens &tdims, int nr, int l)
{
int nthreads = sthread::detach_thread_group::max_parallel_threads;
long per_size1 = tdims.calcUnfoldMaxOffset();
long per_size2 = static_cast<long>(std::pow(tdims.getNVS().getMax(), l));
double lambda = 0.0;
long per_size = sizeof(double)*nr
*static_cast<long>(lambda*per_size1+(1-lambda)*per_size2);
long mem = SystemResources::availableMemory();
int max = 0;
double num_cols = static_cast<double>(mem-magic_mult*nthreads*per_size)
/nthreads/sizeof(double)/nr;
if (num_cols > 0)
{
double maxd = std::pow(num_cols, 1.0/l);
max = static_cast<int>(std::floor(maxd));
}
if (max == 0)
{
max = 10;
JournalRecord rec(journal);
rec << "dim=" << l << " run out of memory, imposing max=" << max;
if (nthreads > 1)
rec << " (decrease number of threads)";
rec << endrec;
}
int avmem_mb = mem/1024/1024;
int tmpmem_mb = nthreads*per_size/1024/1024;
return { max, avmem_mb, tmpmem_mb };
}

View File

@ -1,158 +0,0 @@
@q $Id: faa_di_bruno.cweb 744 2006-05-09 13:16:07Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@ Start of {\tt faa\_di\_bruno.cpp} file.
@s FoldedFineContainer int
@s UnfoldedFineContainer int
@c
#include "faa_di_bruno.h"
#include "fine_container.h"
#include <cmath>
double FaaDiBruno::magic_mult = 1.5;
@<|FaaDiBruno::calculate| folded sparse code@>;
@<|FaaDiBruno::calculate| folded dense code@>;
@<|FaaDiBruno::calculate| unfolded sparse code@>;
@<|FaaDiBruno::calculate| unfolded dense code@>;
@<|FaaDiBruno::estimRefinment| code@>;
@ We take an opportunity to refine the stack container to avoid
allocation of more memory than available.
@<|FaaDiBruno::calculate| folded sparse code@>=
void FaaDiBruno::calculate(const StackContainer<FGSTensor>& cont,
const TensorContainer<FSSparseTensor>& f,
FGSTensor& out)
{
out.zeros();
for (int l = 1; l <= out.dimen(); l++) {
int mem_mb, p_size_mb;
int max = estimRefinment(out.getDims(), out.nrows(), l, mem_mb, p_size_mb);
FoldedFineContainer fine_cont(cont, max);
fine_cont.multAndAdd(l, f, out);
JournalRecord recc(journal);
recc << "dim=" << l << " avmem=" << mem_mb << " tmpmem=" << p_size_mb << " max=" << max
<< " stacks=" << cont.numStacks() << "->" << fine_cont.numStacks() << endrec;
}
}
@ Here we just simply evaluate |multAndAdd| for the dense
container. There is no opportunity for tuning.
@<|FaaDiBruno::calculate| folded dense code@>=
void FaaDiBruno::calculate(const FoldedStackContainer& cont, const FGSContainer& g,
FGSTensor& out)
{
out.zeros();
for (int l = 1; l <= out.dimen(); l++) {
long int mem = SystemResources::availableMemory();
cont.multAndAdd(l, g, out);
JournalRecord rec(journal);
int mem_mb = mem/1024/1024;
rec << "dim=" << l << " avmem=" << mem_mb << endrec;
}
}
@ This is the same as |@<|FaaDiBruno::calculate| folded sparse
code@>|. The only difference is that we construct unfolded fine
container.
@<|FaaDiBruno::calculate| unfolded sparse code@>=
void FaaDiBruno::calculate(const StackContainer<UGSTensor>& cont,
const TensorContainer<FSSparseTensor>& f,
UGSTensor& out)
{
out.zeros();
for (int l = 1; l <= out.dimen(); l++) {
int mem_mb, p_size_mb;
int max = estimRefinment(out.getDims(), out.nrows(), l, mem_mb, p_size_mb);
UnfoldedFineContainer fine_cont(cont, max);
fine_cont.multAndAdd(l, f, out);
JournalRecord recc(journal);
recc << "dim=" << l << " avmem=" << mem_mb << " tmpmem=" << p_size_mb << " max=" << max
<< " stacks=" << cont.numStacks() << "->" << fine_cont.numStacks() << endrec;
}
}
@ Again, no tuning opportunity here.
@<|FaaDiBruno::calculate| unfolded dense code@>=
void FaaDiBruno::calculate(const UnfoldedStackContainer& cont, const UGSContainer& g,
UGSTensor& out)
{
out.zeros();
for (int l = 1; l <= out.dimen(); l++) {
long int mem = SystemResources::availableMemory();
cont.multAndAdd(l, g, out);
JournalRecord rec(journal);
int mem_mb = mem/1024/1024;
rec << "dim=" << l << " avmem=" << mem_mb << endrec;
}
}
@ This function returns a number of maximum rows used for refinement of
the stacked container. We want to set the maximum so that the expected
memory consumption for the number of paralel threads would be less
than available memory. On the other hand we do not want to be too
pesimistic since a very fine refinement can be very slow.
Besides memory needed for a dense unfolded slice of a tensor from
|f|, each thread needs |magic_mult*per_size| bytes of memory. In the
worst case, |magic_mult| will be equal to 2, this means memory
|per_size| for target temporary (permuted symmetry) tensor plus one
copy for intermediate result. However, this shows to be too
pesimistic, so we set |magic_mult| to 1.5. The memory for permuted
symmetry temporary tensor |per_size| is estimated as a weigthed
average of unfolded memory of the |out| tensor and unfolded memory of
a symetric tensor with the largest coordinate size. Some experiments
showed that the best combination of the two is to take 100\% if the
latter, so we set |lambda| to zero.
The |max| number of rows in the refined |cont| must be such that each
slice fits to remaining memory. Number of columns of the slice are
never greater $max^l$. (This is not true, since stacks corresponing to
unit/zero matrices cannot be further refined). We get en equation:
$$nthreads\cdot max^l\cdot 8\cdot r = mem -
magic\_mult\cdot nthreads\cdot per\_size\cdot 8\cdot r,$$
where |mem| is available memory in bytes, |nthreads| is a number of
threads, $r$ is a number of rows, and $8$ is |sizeof(double)|.
If the right hand side is less than zero, we set |max| to 10, just to
let it do something.
@<|FaaDiBruno::estimRefinment| code@>=
int FaaDiBruno::estimRefinment(const TensorDimens& tdims, int nr, int l,
int& avmem_mb, int& tmpmem_mb)
{
int nthreads = THREAD_GROUP::max_parallel_threads;
long int per_size1 = tdims.calcUnfoldMaxOffset();
long int per_size2 = (long int)pow((double)tdims.getNVS().getMax(), l);
double lambda = 0.0;
long int per_size = sizeof(double)*nr
*(long int)(lambda*per_size1+(1-lambda)*per_size2);
long int mem = SystemResources::availableMemory();
int max = 0;
double num_cols = ((double)(mem-magic_mult*nthreads*per_size))
/nthreads/sizeof(double)/nr;
if (num_cols > 0) {
double maxd = pow(num_cols, ((double)1)/l);
max = (int)floor(maxd);
}
if (max == 0) {
max = 10;
JournalRecord rec(journal);
rec << "dim=" << l << " run out of memory, imposing max=" << max;
if (nthreads > 1)
rec << " (decrease number of threads)";
rec << endrec;
}
avmem_mb = mem/1024/1024;
tmpmem_mb = (nthreads*per_size)/1024/1024;
return max;
}
@ End of {\tt faa\_di\_bruno.cpp} file.

View File

@ -0,0 +1,66 @@
/*
* Copyright © 2005 Ondra Kamenik
* 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/>.
*/
// Faà Di Bruno evaluator
/* This defines a class which implements the Faà Di Bruno Formula
[B_s]_αα = [f_zˡ]_ββ [z_{s^|c|}]_c(α)^β
c, ¹
where s is a general symmetry of dimension k and z is a stack of
functions. */
#ifndef FAA_DI_BRUNO_H
#define FAA_DI_BRUNO_H
#include "journal.hh"
#include "stack_container.hh"
#include "t_container.hh"
#include "sparse_tensor.hh"
#include "gs_tensor.hh"
#include <tuple>
class FaaDiBruno
{
Journal &journal;
public:
FaaDiBruno(Journal &jr)
: journal(jr)
{
}
void calculate(const StackContainer<FGSTensor> &cont, const TensorContainer<FSSparseTensor> &f,
FGSTensor &out);
void calculate(const FoldedStackContainer &cont, const FGSContainer &g,
FGSTensor &out);
void calculate(const StackContainer<UGSTensor> &cont, const TensorContainer<FSSparseTensor> &f,
UGSTensor &out);
void calculate(const UnfoldedStackContainer &cont, const UGSContainer &g,
UGSTensor &out);
protected:
std::tuple<int,int,int> estimRefinement(const TensorDimens &tdims, int nr, int l);
// See FaaDiBruno::calculate() folded sparse code for why we have magic_mult
constexpr static double magic_mult = 1.5;
};
#endif

Some files were not shown because too many files have changed in this diff Show More