├── .gitignore ├── .travis.yml ├── DCO1.1.txt ├── LICENSE.txt ├── Makefile ├── README.md ├── docs ├── Makefile ├── README.md ├── cheatsheet.md ├── conf.py ├── developers.md ├── index.html ├── index.rst └── inference.md ├── notebooks ├── coin.ipynb ├── error_reporting.ipynb └── slicstan.ipynb ├── setup.py ├── tests ├── __init__.py ├── runtime │ ├── __init__.py │ ├── test_coin.py │ ├── test_gaussian_process.py │ ├── test_gradient_warn.py │ ├── test_kmeans.py │ ├── test_logistic.py │ ├── test_missing_data.py │ ├── test_regression.py │ ├── test_regression_matrix.py │ ├── test_row_vector_expr_terms.py │ ├── test_schools.py │ ├── test_squared_error.py │ ├── test_validate_arr_expr_primitives.py │ ├── test_vectorized_probability.py │ └── utils.py ├── stan │ ├── ch02_02_comment.stan │ ├── ch02_02_include.stan │ ├── ch02_02_inline.stan │ ├── ch02_02_std_normal.stan │ ├── ch03_03_bound_1.stan │ ├── ch03_03_bound_2.stan │ ├── ch04_11_chain_rule.stan │ ├── ch05_9_print.stan │ ├── ch06_2_variables.stan │ ├── ch09_regression.stan │ ├── ch09_regression_bernoulli.stan │ ├── ch09_regression_matrix.stan │ ├── ch09_regression_qr.stan │ ├── ch10_time_ar_1.stan │ ├── ch10_time_ar_k.stan │ ├── ch10_time_arch_1.stan │ ├── ch10_time_arma_1_1.stan │ ├── ch10_time_garch_1_1.stan │ ├── ch10_time_hmm_supervised.stan │ ├── ch10_time_ma_2.stan │ ├── ch10_time_ma_q.stan │ ├── ch10_time_svm.stan │ ├── ch11_loading_matrix.stan │ ├── ch11_missing_data.stan │ ├── ch11_partially_known_paramters.stan │ ├── ch11_sliced_missing_data.stan │ ├── ch12_estimate_censored.stan │ ├── ch12_integrate_censored.stan │ ├── ch12_integrate_censored_2.stan │ ├── ch12_truncated.stan │ ├── ch13_log_sum_of_exp.stan │ ├── ch13_zero_inflation.stan │ ├── ch14_regression_error.stan │ ├── ch14_rounding.stan │ ├── ch14_rounding_2.stan │ ├── ch15_change_point.stan │ ├── ch15_cormack_jolly_seber.stan │ ├── ch15_dawid_skene.stan │ ├── ch15_lincoln_petersen.stan │ ├── ch17_k_means.stan │ ├── ch17_lda.stan │ ├── ch17_naive_bayes.stan │ ├── ch18_fitting_gaussian_process.stan │ ├── ch18_gaussian_process.stan │ ├── ch18_gaussian_process_2.stan │ ├── ch18_latent_gaussian_process.stan │ ├── ch18_multiple_outputs.stan │ ├── ch18_predictive_inference.stan │ ├── ch18_predictive_inference_2.stan │ ├── ch18_predictive_inference_3.stan │ ├── ch18_relevance_determination.stan │ ├── ch21_oscillator.stan │ ├── ch21_oscillator_2.stan │ ├── ch21_oscillator_estimation.stan │ ├── ch22_3_change.stan │ ├── ch22_3_transform.stan │ ├── ch23_1_triangle.stan │ ├── ch24_1_relative_diff.stan │ ├── ch24_2_function_as_statement.stan │ ├── ch25_fits1.stan │ ├── ch25_fits2.stan │ ├── ch28_11_standardizing_1.stan │ ├── ch28_11_standardizing_2.stan │ ├── ch28_8_bernoulli.stan │ ├── ch28_neal_1.stan │ ├── ch28_neal_2.stan │ ├── ch28_vectorization_1.stan │ ├── ch28_vectorization_2.stan │ ├── ch28_vectorization_3.stan │ ├── ch28_vectorized_probability.stan │ ├── ch31_square_error.stan │ ├── ch34_2_sampling.stan │ ├── coin.stan │ ├── fun.stan │ ├── fundecl.stan │ ├── slice.stan │ ├── slice2.stan │ ├── slicstan.stan │ ├── test_stan.py │ └── types.stan └── yaps │ ├── coin.py │ ├── coin_verbose.py │ ├── regression.py │ ├── regression_bernoulli.py │ ├── regression_matrix.py │ ├── regression_qr.py │ ├── slicstan.py │ ├── stan_types.py │ └── truncated.py └── yaps ├── __init__.py ├── decorator.py ├── ir.py ├── labeled_strings.py ├── lib.py ├── py2ir.py ├── roundtrip.py ├── stan.g4 ├── stan2yaps.py ├── stanLexer.py ├── stanListener.py └── stanParser.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .ipynb_checkpoints 3 | .vscode 4 | .antlr 5 | *.interp 6 | *.tokens 7 | /build/ 8 | /dist/ 9 | /yaps.egg-info/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | cache: pip 3 | dist: xenial 4 | python: 5 | - "3.6" 6 | # command to install dependencies 7 | before_install: 8 | - sudo apt-get install -y antlr4 9 | install: 10 | - pip install --upgrade pip 11 | # command to run tests 12 | before_script: 13 | - make 14 | - wget https://github.com/stan-dev/cmdstan/releases/download/v2.18.0/cmdstan-2.18.0.tar.gz 15 | - tar -xvf cmdstan-2.18.0.tar.gz > /dev/null 16 | - cd cmdstan-2.18.0 && make build -j4 > /dev/null && cd .. 17 | - export CMDSTAN=`pwd`/'cmdstan-2.18.0' 18 | - pip install nose pycmdstan 19 | - pip install . 20 | script: 21 | - make test -------------------------------------------------------------------------------- /DCO1.1.txt: -------------------------------------------------------------------------------- 1 | Developer's Certificate of Origin 1.1 2 | 3 | By making a contribution to this project, I certify that: 4 | 5 | (a) The contribution was created in whole or in part by me and I 6 | have the right to submit it under the open source license 7 | indicated in the file; or 8 | 9 | (b) The contribution is based upon previous work that, to the best 10 | of my knowledge, is covered under an appropriate open source 11 | license and I have the right under that license to submit that 12 | work with modifications, whether created in whole or in part 13 | by me, under the same open source license (unless I am 14 | permitted to submit under a different license), as indicated 15 | in the file; or 16 | 17 | (c) The contribution was provided directly to me by some other 18 | person who certified (a), (b) or (c) and I have not modified 19 | it. 20 | 21 | (d) I understand and agree that this project and the contribution 22 | are public and that a record of the contribution (including all 23 | personal information I submit with it, including my sign-off) is 24 | maintained indefinitely and may be redistributed consistent with 25 | this project or the open source license(s) involved. 26 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2017-2018 IBM Corporation 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: yaps/stanLexer.py yaps/stanParser.py 2 | 3 | yaps/stanLexer.py yaps/stanParser.py: yaps/stan.g4 4 | antlr4 -Dlanguage=Python3 yaps/stan.g4 5 | 6 | test: 7 | nosetests -v tests/stan/test_stan.py . 8 | 9 | doc: 10 | cp README.md docs/ 11 | 12 | distrib: 13 | python setup.py sdist bdist_wheel 14 | 15 | upload: 16 | twine upload dist/* 17 | 18 | clean: 19 | -rm -f yaps/stan.tokens yaps/stanLexer.tokens \ 20 | yaps/stan.interp yaps/stanLexer.interp 21 | -rm -rf __pycache__ yaps/__pycache__ 22 | 23 | cleanall: clean 24 | -rm -f *~ */*~ */*/*~ 25 | cd docs; make clean 26 | -rm -rf build/ 27 | -rm -rf dist/ 28 | -rm -rf yaps.egg-info 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/IBM/yaps.svg?branch=master)](https://travis-ci.org/IBM/yaps) [![PyPI version](https://badge.fury.io/py/yaps.svg)](https://badge.fury.io/py/yaps) [![Documentation Status](https://readthedocs.org/projects/yaps/badge/?version=latest)](https://yaps.readthedocs.io/en/latest/?badge=latest) 2 | 3 | # YAPS 4 | 5 | Yaps is a new surface language for [Stan](http://mc-stan.org/). It lets 6 | users write Stan programs using Python syntax. For example, consider the 7 | following Stan program, which models tosses `x` of a coin with bias `theta`: 8 | ```stan 9 | data { 10 | int x[10]; 11 | } 12 | parameters { 13 | real theta; 14 | } 15 | model { 16 | theta ~ uniform(0,1); 17 | for (i in 1:10) 18 | x[i] ~ bernoulli(theta); 19 | } 20 | ``` 21 | It can be rewritten in Python has follows: 22 | ```python 23 | import yaps 24 | from yaps.lib import int, real, uniform, bernoulli 25 | 26 | @yaps.model 27 | def coin(x: int(lower=0, upper=1)[10]): 28 | theta: real(lower=0, upper=1) <~ uniform(0, 1) 29 | for i in range(1,11): 30 | x[i] <~ bernoulli(theta) 31 | ``` 32 | 33 | The `@yaps.model` decorator indicates that the function following it 34 | is a Stan program. While being syntactically Python, it is 35 | semantically reinterpreted as Stan. 36 | 37 | The argument of the function corresponds to the `data` block. The 38 | type of the data must be declared. Here, you can see that `x` is an 39 | array of 10 integers between `0` and `1` (`int(lower=0, upper=1)[10]`). 40 | 41 | Parameters are declared as variables with their type in the body of 42 | the function. Their prior can be defined using the sampling operator 43 | `<~` (or `is`). 44 | 45 | The body of the function corresponds to the Stan model. Python syntax 46 | is used for the imperative constructs of the model, like the `for` 47 | loop in the example. The operator `<~` is used to represent sampling 48 | and `x.T[a,b]` for truncated distribution. 49 | 50 | Note that Stan array are 1-based. The range of the loop is thus `range(1, 11)`, 51 | that is 1,2, ... 10. 52 | 53 | Other Stan blocks can be introduced using the `with` syntax of Python. 54 | For example, the previous program could also be written as follows: 55 | ```python 56 | @yaps.model 57 | def coin(x: int(lower=0, upper=1)[10]): 58 | with parameters: 59 | theta: real(lower=0, upper=1) 60 | with model: 61 | theta <~ uniform(0, 1) 62 | for i in range(1,11): 63 | x[i] <~ bernoulli(theta) 64 | ``` 65 | 66 | The corresponding Stan program can be displayed using the `print` function: 67 | ```python 68 | print(coin) 69 | ``` 70 | 71 | Finally, it is possible to launch Bayesian inference on the defined model applied to some data. 72 | The communication with the Stan inference engine is based on on [PyCmdStan](https://pycmdstan.readthedocs.io/en/latest/). 73 | ```python 74 | flips = np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 1]) 75 | constrained_coin = coin(x=flips) 76 | constrained_coin.sample(data=constrained_coin.data) 77 | ``` 78 | Note that arrays must be cast into numpy arrays (see pycmdstan documentation). 79 | 80 | After the inference the attribute `posterior` of the constrained model is an object with fields for the latent model parameters: 81 | ```python 82 | theta_mean = constrained_coin.posterior.theta.mean() 83 | print("mean of theta: {:.3f}".format(theta_mean)) 84 | ``` 85 | 86 | Yaps provides a lighter syntax to Stan programs. Since Yaps uses Python syntax, users can take advantage of Python tooling 87 | for syntax highlighting, indentation, error reporting, ... 88 | 89 | ## Install 90 | 91 | Yaps depends on the following python packages: 92 | - astor 93 | - graphviz 94 | - antlr4-python3-runtime 95 | - pycmdstan 96 | 97 | To install Yaps and all its dependencies run: 98 | ``` 99 | pip install yaps 100 | ``` 101 | 102 | To install from source, first clone the repo, then: 103 | ``` 104 | pip install . 105 | ``` 106 | 107 | By default, communication with the Stan inference engine is based on [PyCmdStan](https://pycmdstan.readthedocs.io/en/latest/). To run inference, you first need to install [CmdStan](http://mc-stan.org/users/interfaces/cmdstan) and set the CMDSTAN environment variable to point to your CmdStan directory. 108 | 109 | ``` 110 | export CMDSTAN=/path/to/cmdstan 111 | ``` 112 | 113 | ## Tools 114 | 115 | We provide a tool to compile Stan files to Yaps syntax. 116 | For instance, if `path/to/coin.stan` contain the Stan model presented at the beginning, then: 117 | ``` 118 | stan2yaps path/to/coin.stan 119 | ``` 120 | outputs: 121 | ``` 122 | # ------------- 123 | # tests/stan/coin.stan 124 | # ------------- 125 | @yaps.model 126 | def stan_model(x: int(lower=0, upper=1)[10]): 127 | theta: real 128 | theta is uniform(0.0, 1.0) 129 | for i in range(1, 10 + 1): 130 | x[(i),] is bernoulli(theta) 131 | print(x) 132 | ``` 133 | 134 | Compilers from Yaps to Stan and from Stan to Yaps can also be invoked programmatically using the following functions: 135 | ```python 136 | yaps.from_stan(code_string=None, code_file=None) # Compile a Stan model to Yaps 137 | yaps.to_stan(code_string=None, code_file=None) # Compile a Yaps model to Stan 138 | ``` 139 | 140 | ## Documentation 141 | 142 | The full documentation is available at https://yaps.readthedocs.io. You can find more details in the following [article](https://arxiv.org/abs/1812.04125): 143 | ``` 144 | @article{2018-yaps-stan, 145 | author = {Baudart, Guillaume and Hirzel, Martin and Kate, Kiran and Mandel, Louis and Shinnar, Avraham}, 146 | title = "{Yaps: Python Frontend to Stan}", 147 | journal = {arXiv e-prints}, 148 | year = 2018, 149 | month = Dec, 150 | url = {https://arxiv.org/abs/1812.04125}, 151 | } 152 | ``` 153 | 154 | 155 | ## License 156 | 157 | Yaps is distributed under the terms of the Apache 2.0 License, see 158 | [LICENSE.txt](LICENSE.txt) 159 | 160 | 161 | 162 | ## Contributions 163 | 164 | Yaps is still at an early phase of development and we welcome 165 | contributions. Contributors are expected to submit a 'Developer's 166 | Certificate of Origin', which can be found in [DCO1.1.txt](DCO1.1.txt). 167 | 168 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = Yaps 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/IBM/yaps.svg?branch=master)](https://travis-ci.org/IBM/yaps) [![PyPI version](https://badge.fury.io/py/yaps.svg)](https://badge.fury.io/py/yaps) [![Documentation Status](https://readthedocs.org/projects/yaps/badge/?version=latest)](https://yaps.readthedocs.io/en/latest/?badge=latest) 2 | 3 | # YAPS 4 | 5 | Yaps is a new surface language for [Stan](http://mc-stan.org/). It lets 6 | users write Stan programs using Python syntax. For example, consider the 7 | following Stan program, which models tosses `x` of a coin with bias `theta`: 8 | ```stan 9 | data { 10 | int x[10]; 11 | } 12 | parameters { 13 | real theta; 14 | } 15 | model { 16 | theta ~ uniform(0,1); 17 | for (i in 1:10) 18 | x[i] ~ bernoulli(theta); 19 | } 20 | ``` 21 | It can be rewritten in Python has follows: 22 | ```python 23 | import yaps 24 | from yaps.lib import int, real, uniform, bernoulli 25 | 26 | @yaps.model 27 | def coin(x: int(lower=0, upper=1)[10]): 28 | theta: real(lower=0, upper=1) <~ uniform(0, 1) 29 | for i in range(1,11): 30 | x[i] <~ bernoulli(theta) 31 | ``` 32 | 33 | The `@yaps.model` decorator indicates that the function following it 34 | is a Stan program. While being syntactically Python, it is 35 | semantically reinterpreted as Stan. 36 | 37 | The argument of the function corresponds to the `data` block. The 38 | type of the data must be declared. Here, you can see that `x` is an 39 | array of 10 integers between `0` and `1` (`int(lower=0, upper=1)[10]`). 40 | 41 | Parameters are declared as variables with their type in the body of 42 | the function. Their prior can be defined using the sampling operator 43 | `<~` (or `is`). 44 | 45 | The body of the function corresponds to the Stan model. Python syntax 46 | is used for the imperative constructs of the model, like the `for` 47 | loop in the example. The operator `<~` is used to represent sampling 48 | and `x.T[a,b]` for truncated distribution. 49 | 50 | Note that Stan array are 1-based. The range of the loop is thus `range(1, 11)`, 51 | that is 1,2, ... 10. 52 | 53 | Other Stan blocks can be introduced using the `with` syntax of Python. 54 | For example, the previous program could also be written as follows: 55 | ```python 56 | @yaps.model 57 | def coin(x: int(lower=0, upper=1)[10]): 58 | with parameters: 59 | theta: real(lower=0, upper=1) 60 | with model: 61 | theta <~ uniform(0, 1) 62 | for i in range(1,11): 63 | x[i] <~ bernoulli(theta) 64 | ``` 65 | 66 | The corresponding Stan program can be displayed using the `print` function: 67 | ```python 68 | print(coin) 69 | ``` 70 | 71 | Finally, it is possible to launch Bayesian inference on the defined model applied to some data. 72 | The communication with the Stan inference engine is based on on [PyCmdStan](https://pycmdstan.readthedocs.io/en/latest/). 73 | ```python 74 | flips = np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 1]) 75 | constrained_coin = coin(x=flips) 76 | constrained_coin.sample(data=constrained_coin.data) 77 | ``` 78 | Note that arrays must be cast into numpy arrays (see pycmdstan documentation). 79 | 80 | After the inference the attribute `posterior` of the constrained model is an object with fields for the latent model parameters: 81 | ```python 82 | theta_mean = constrained_coin.posterior.theta.mean() 83 | print("mean of theta: {:.3f}".format(theta_mean)) 84 | ``` 85 | 86 | Yaps provides a lighter syntax to Stan programs. Since Yaps uses Python syntax, users can take advantage of Python tooling 87 | for syntax highlighting, indentation, error reporting, ... 88 | 89 | ## Install 90 | 91 | Yaps depends on the following python packages: 92 | - astor 93 | - graphviz 94 | - antlr4-python3-runtime 95 | - pycmdstan 96 | 97 | To install Yaps and all its dependencies run: 98 | ``` 99 | pip install yaps 100 | ``` 101 | 102 | To install from source, first clone the repo, then: 103 | ``` 104 | pip install . 105 | ``` 106 | 107 | By default, communication with the Stan inference engine is based on [PyCmdStan](https://pycmdstan.readthedocs.io/en/latest/). To run inference, you first need to install [CmdStan](http://mc-stan.org/users/interfaces/cmdstan) and set the CMDSTAN environment variable to point to your CmdStan directory. 108 | 109 | ``` 110 | export CMDSTAN=/path/to/cmdstan 111 | ``` 112 | 113 | ## Tools 114 | 115 | We provide a tool to compile Stan files to Yaps syntax. 116 | For instance, if `path/to/coin.stan` contain the Stan model presented at the beginning, then: 117 | ``` 118 | stan2yaps path/to/coin.stan 119 | ``` 120 | outputs: 121 | ``` 122 | # ------------- 123 | # tests/stan/coin.stan 124 | # ------------- 125 | @yaps.model 126 | def stan_model(x: int(lower=0, upper=1)[10]): 127 | theta: real 128 | theta is uniform(0.0, 1.0) 129 | for i in range(1, 10 + 1): 130 | x[(i),] is bernoulli(theta) 131 | print(x) 132 | ``` 133 | 134 | Compilers from Yaps to Stan and from Stan to Yaps can also be invoked programmatically using the following functions: 135 | ```python 136 | yaps.from_stan(code_string=None, code_file=None) # Compile a Stan model to Yaps 137 | yaps.to_stan(code_string=None, code_file=None) # Compile a Yaps model to Stan 138 | ``` 139 | 140 | ## Documentation 141 | 142 | The full documentation is available at https://yaps.readthedocs.io. You can find more details in the following [article](https://arxiv.org/abs/1812.04125): 143 | ``` 144 | @article{2018-yaps-stan, 145 | author = {Baudart, Guillaume and Hirzel, Martin and Kate, Kiran and Mandel, Louis and Shinnar, Avraham}, 146 | title = "{Yaps: Python Frontend to Stan}", 147 | journal = {arXiv e-prints}, 148 | year = 2018, 149 | month = Dec, 150 | url = {https://arxiv.org/abs/1812.04125}, 151 | } 152 | ``` 153 | 154 | 155 | ## License 156 | 157 | Yaps is distributed under the terms of the Apache 2.0 License, see 158 | [LICENSE.txt](LICENSE.txt) 159 | 160 | 161 | 162 | ## Contributions 163 | 164 | Yaps is still at an early phase of development and we welcome 165 | contributions. Contributors are expected to submit a 'Developer's 166 | Certificate of Origin', which can be found in [DCO1.1.txt](DCO1.1.txt). 167 | 168 | -------------------------------------------------------------------------------- /docs/cheatsheet.md: -------------------------------------------------------------------------------- 1 | # Yaps Modeling Language 2 | 3 | A Yaps model is a Python function prefixed by the `@yaps.model` decorator. 4 | 5 | ```python 6 | import yaps 7 | from yaps.lib import int, real, uniform, bernoulli 8 | 9 | @yaps.model 10 | def coin(x: int(lower=0, upper=1)[10]): 11 | theta: real(lower=0, upper=1) <~ uniform(0, 1) 12 | for i in range(10): 13 | x[i] <~ bernoulli(theta) 14 | ``` 15 | 16 | Types definitions, e.g., `int` and `real`, and Stan functions are defined in `yaps.lib`. 17 | 18 | Below are examples of Yaps code with the corresponding Stan code. 19 | 20 | ## Comments 21 | 22 | ```python 23 | # This is a comment 24 | x <~ Normal(0,1) # This is a comment 25 | ``` 26 | 27 | ## Data Types and Variable Declarations 28 | 29 | ```python 30 | # Yaps # Stan 31 | ############################################################################ 32 | x: int # int x; 33 | x: real # real x; 34 | 35 | x: real[10] # real x[10]; 36 | m: matrix[6,7] [3,3] # matrix[3,3] m[6,7]; 37 | 38 | N: int(lower=1) # int N; 39 | log_p: real(upper=0) # real log_p; 40 | rho: vector(lower=-1,upper=1)[3] # vector[3] rho; 41 | 42 | mu: vector[7][3] # vector[7] mu[3]; 43 | mu: matrix[7,2] [15,12] # matrix[7,2] mu[15,12]; 44 | 45 | x = w[5] # x = w[5]; 46 | c = a[1,3] # c = a[1,3]; 47 | a: matrix[3,2] = 0.5 * (b + c) # matrix[3,2] a = 0.5 * (b + c); 48 | ``` 49 | 50 | ## Expressions 51 | 52 | ```python 53 | m1: matrix[3,2] = [[1,2],[3,4],[5,6]] # matrix[3,2] m1 = [[1,2],[3,4],[5,6]]; 54 | vX: vector[2] = [1,10].transpose # vector[2] vX = [1,10]'; 55 | a: int[3] = {1,10,1000} # int a[3] = {1,10,100}; 56 | b: int[2,3] = {{1,2,3},{4,5,6}} # int b[2,3] = {{1,2,3},{4,5,6}}; 57 | 58 | 3.0+0.14 59 | -15 60 | 2*3+1 61 | (x-y)/2.0 62 | (n*(n+1))/2 63 | x/n 64 | m%n 65 | 66 | 3**2 # 3^2 67 | c = a.pmult(b) # c = a .* b 68 | c = a.pdiv(b) # c = a ./ b 69 | b if a else c # a?b:c 70 | 71 | x[4] 72 | x[4,:] # x[4,] or x[4,:] 73 | ``` 74 | 75 | ## Statements 76 | 77 | ```python 78 | target += -0.5 * y * y # target += -0.5 * y * y; 79 | y <~ normal(mu, sigma) # y ~ normal(mu,sigma); 80 | y is normal(mu, sigma) # y ~ normal(mu,sigma); 81 | y <~ normal(0,1).T[-0.5, 2.1] # y ~ normal(0, 1) T[-0.5, 2.1]; 82 | 83 | for n in range(1,N+1): ... # for (n in 1:N) {...} 84 | while cond: ... # while (cond) {...} 85 | if cond: ... # if (cond) {...} 86 | else: ... # else {...} 87 | 88 | break # break; 89 | continue # continue; 90 | pass # //nothing 91 | 92 | with block: # { 93 | ... # ... 94 | # } 95 | ``` 96 | 97 | Warning: `range(n)` in python denotes integers from 0 to n-1. 98 | In Stan indexes starts from 1 (`for i in 1:n`). 99 | The correct translation for `for i in 1:n` is thus `for i in range(1, n+1)`. 100 | 101 | ## Program Blocks 102 | 103 | - The keyword arguments of the Yaps model function are Stan data. 104 | - Yaps top-level declarations are parsed as Stan parameters. 105 | - Yaps top-level statements define the Stan model. 106 | 107 | ```python 108 | def model(x: real): # data {int x;} 109 | mu: real # parameters {real mu;} 110 | x <~ normal(mu, 1) # model { x ~ normal(mu, 1)} 111 | ``` 112 | 113 | Yaps also supports a fully annotated syntax where blocks are introduced via python `with` statements 114 | 115 | ```python 116 | with functions: ... # function {...} 117 | with transformed_data # transformed data {...} 118 | with parameters: ... # parameters {...} 119 | with transformed_parameters: ... # transformed parameters {...} 120 | with model: ... # model {...} 121 | with generated quantities: ... # generated quantities {...} 122 | ``` 123 | 124 | ## Function Definitions 125 | 126 | User-defined functions must be defined inside the model in the `functions` block. Their syntax follows Python syntax with type annotations 127 | 128 | ```python 129 | with functions: # funtions { 130 | def successor(x: int) -> int: # int successor(int x) { 131 | return x + 1 # return x + 1; 132 | # } 133 | # } 134 | ``` 135 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Yaps documentation build configuration file, created by 5 | # sphinx-quickstart on Thu Oct 18 13:30:19 2018. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | # 20 | # import os 21 | # import sys 22 | # sys.path.insert(0, os.path.abspath('.')) 23 | 24 | 25 | # -- General configuration ------------------------------------------------ 26 | 27 | # If your documentation needs a minimal Sphinx version, state it here. 28 | # 29 | # needs_sphinx = '1.0' 30 | 31 | source_parsers = { 32 | '.md': 'recommonmark.parser.CommonMarkParser', 33 | } 34 | 35 | 36 | # Add any Sphinx extension module names here, as strings. They can be 37 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 38 | # ones. 39 | extensions = ['sphinx.ext.viewcode', 40 | 'sphinx.ext.githubpages'] 41 | 42 | # Add any paths that contain templates here, relative to this directory. 43 | templates_path = ['_templates'] 44 | 45 | # The suffix(es) of source filenames. 46 | # You can specify multiple suffix as a list of string: 47 | # 48 | # source_suffix = ['.rst', '.md'] 49 | source_suffix = ['.rst', '.md'] 50 | 51 | # The master toctree document. 52 | master_doc = 'index' 53 | 54 | # General information about the project. 55 | project = 'Yaps' 56 | copyright = '2018, Guillaume Baudart, Martin Hirzel, Kiran Kate, Louis Mandel, Avraham Shinnar' 57 | author = 'Guillaume Baudart, Martin Hirzel, Kiran Kate, Louis Mandel, Avraham Shinnar' 58 | 59 | # The version info for the project you're documenting, acts as replacement for 60 | # |version| and |release|, also used in various other places throughout the 61 | # built documents. 62 | 63 | version = '0.1.4' 64 | release = version 65 | 66 | # The language for content autogenerated by Sphinx. Refer to documentation 67 | # for a list of supported languages. 68 | # 69 | # This is also used if you do content translation via gettext catalogs. 70 | # Usually you set "language" from the command line for these cases. 71 | language = None 72 | 73 | # List of patterns, relative to source directory, that match files and 74 | # directories to ignore when looking for source files. 75 | # This patterns also effect to html_static_path and html_extra_path 76 | exclude_patterns = [] 77 | 78 | # The name of the Pygments (syntax highlighting) style to use. 79 | pygments_style = 'sphinx' 80 | 81 | # If true, `todo` and `todoList` produce output, else they produce nothing. 82 | todo_include_todos = False 83 | 84 | 85 | # -- Options for HTML output ---------------------------------------------- 86 | 87 | # The theme to use for HTML and HTML Help pages. See the documentation for 88 | # a list of builtin themes. 89 | # 90 | html_theme = 'sphinx_rtd_theme' 91 | 92 | # Theme options are theme-specific and customize the look and feel of a theme 93 | # further. For a list of options available for each theme, see the 94 | # documentation. 95 | # 96 | # html_theme_options = {} 97 | 98 | # Add any paths that contain custom static files (such as style sheets) here, 99 | # relative to this directory. They are copied after the builtin static files, 100 | # so a file named "default.css" will overwrite the builtin "default.css". 101 | html_static_path = ['_static'] 102 | 103 | # Custom sidebar templates, must be a dictionary that maps document names 104 | # to template names. 105 | # 106 | # This is required for the alabaster theme 107 | # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars 108 | html_sidebars = { 109 | '**': [ 110 | 'relations.html', # needs 'show_related': True theme option to display 111 | 'searchbox.html', 112 | ] 113 | } 114 | 115 | 116 | # -- Options for HTMLHelp output ------------------------------------------ 117 | 118 | # Output file base name for HTML help builder. 119 | htmlhelp_basename = 'Yapsdoc' 120 | 121 | 122 | # -- Options for LaTeX output --------------------------------------------- 123 | 124 | latex_elements = { 125 | # The paper size ('letterpaper' or 'a4paper'). 126 | # 127 | # 'papersize': 'letterpaper', 128 | 129 | # The font size ('10pt', '11pt' or '12pt'). 130 | # 131 | # 'pointsize': '10pt', 132 | 133 | # Additional stuff for the LaTeX preamble. 134 | # 135 | # 'preamble': '', 136 | 137 | # Latex figure (float) alignment 138 | # 139 | # 'figure_align': 'htbp', 140 | } 141 | 142 | # Grouping the document tree into LaTeX files. List of tuples 143 | # (source start file, target name, title, 144 | # author, documentclass [howto, manual, or own class]). 145 | latex_documents = [ 146 | (master_doc, 'Yaps.tex', 'Yaps Documentation', 147 | 'Guillaume Baudart, Martin Hirzel, Kiran Kate, Louis Mandel, Avraham Shinnar', 'manual'), 148 | ] 149 | 150 | 151 | # -- Options for manual page output --------------------------------------- 152 | 153 | # One entry per manual page. List of tuples 154 | # (source start file, name, description, authors, manual section). 155 | man_pages = [ 156 | (master_doc, 'yaps', 'Yaps Documentation', 157 | [author], 1) 158 | ] 159 | 160 | 161 | # -- Options for Texinfo output ------------------------------------------- 162 | 163 | # Grouping the document tree into Texinfo files. List of tuples 164 | # (source start file, target name, title, author, 165 | # dir menu entry, description, category) 166 | texinfo_documents = [ 167 | (master_doc, 'Yaps', 'Yaps Documentation', 168 | author, 'Yaps', 'One line description of project.', 169 | 'Miscellaneous'), 170 | ] 171 | -------------------------------------------------------------------------------- /docs/developers.md: -------------------------------------------------------------------------------- 1 | # For Developers 2 | 3 | To build the parser, you need to install [antlr4](http://www.antlr.org/) before installing the package. 4 | To test your model with the Stan inference engine, you need to install [cmdstan](http://mc-stan.org/users/interfaces/cmdstan). 5 | Then install the dependencies. 6 | 7 | ``` 8 | pip install nose astor graphviz antlr4-python3-runtime pycmdstan 9 | make 10 | export CMDSTAN='path/to/cmdstan-dir' 11 | make test 12 | ``` 13 | 14 | To test the round trip on only one file, after the install: 15 | ``` 16 | yaps-roundtrip path/to/file.stan 17 | ``` 18 | 19 | ## Documentation 20 | 21 | The documentation is hosted by [ReadTheDocs](https://yaps.readthedocs.io). 22 | To keep the README in sync with the doc: 23 | ``` 24 | make doc 25 | ``` 26 | 27 | ## Distribution 28 | 29 | To create a new distribution you need the following packages: 30 | ``` 31 | pip install setuptools wheel twine 32 | ``` 33 | 34 | Then to build the new distribution and upload it: 35 | ``` 36 | make distrib 37 | make upload 38 | ``` 39 | Note: you need valid PyPI credentials to upload the package. 40 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Yaps documentation master file, created by 2 | sphinx-quickstart on Thu Oct 18 13:30:19 2018. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Yaps's documentation! 7 | ================================ 8 | 9 | Yaps is a new surface language for programming `Stan `_ models using python syntax. 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | README 15 | cheatsheet 16 | inference 17 | developers 18 | 19 | 20 | Links 21 | ----- 22 | 23 | - Stan: http://mc-stan.org/ 24 | - PyStan: https://pystan.readthedocs.io 25 | - PyCmdStan: https://pycmdstan.readthedocs.io -------------------------------------------------------------------------------- /docs/inference.md: -------------------------------------------------------------------------------- 1 | # Inference 2 | 3 | By default, communication with the Stan inference engine is based on [PyCmdStan](https://pycmdstan.readthedocs.io/en/latest/). 4 | A constrained model can be defined by passing concrete values for the data. 5 | This constrained model is linked to a PyCmdStan model. 6 | It is thus possible to invoke the pycmdstan methods `sample`, `run`, `optimize`, or `variational` to launch the inference. 7 | After the inference, the result is stored in the `posterior` attribute of the constrained model as an object with one field for each learned parameter. 8 | 9 | For example: 10 | ``` 11 | @yaps.model 12 | def coin(x: int(lower=0, upper=1)[10]): 13 | theta: real(lower=0, upper=1) is uniform(0, 1) 14 | for i in range(2, 11): 15 | x[i] is bernoulli(theta) 16 | 17 | 18 | flips = np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 1]) 19 | 20 | constrained_coin = coin(x=flips) 21 | constrained_coin.sample(data=constrained_coin.data) 22 | theta_mean = constrained_coin.posterior.theta.mean() 23 | print("mean of theta: {:.3f}".format(theta_mean)) 24 | ``` 25 | 26 | Errors detected by the Stan compiler and runtime are mapped to the original yaps code. 27 | 28 | Note that this interface takes full advantage of the features offered by PyCmdStan. 29 | In particular, models are cached and only recompiled when a change is detected even if the rest of the python script has changed. 30 | 31 | ## PyStan Wrapper 32 | 33 | Yaps also offer a limited wrapper for the [PyStan](https://pystan.readthedocs.io/en/latest/) interface. 34 | For instance, the inference part of the previous example can be rewritten: 35 | 36 | ``` 37 | fit = yaps.apply(pystan.stan, constrained_coin) 38 | theta_mean = fit.extract()['theta'].mean() 39 | print("mean of theta: {:.3f}".format(theta_mean)) 40 | ``` 41 | 42 | The wrapper is used to map the errors back to the original yaps code. 43 | 44 | 45 | ## Direct API use 46 | 47 | Finally it is possible to use yaps only as a compiler and rely on the existing API for PyCmdStan or PyStan. 48 | For every decorated yaps model `model`, the string `str(model)` contains the compiled Stan code. 49 | 50 | Using PyCmdStan the previous example becomes: 51 | ``` 52 | coin_dat = {'x': np.array([1,0,1,0,1,0,0,0,0,1])} 53 | coin_model = pycmdstan.Model(code = str(coin)) 54 | fit = coin_model.sample(data = coin_dat) 55 | theta_mean = fit.csv['theta'].mean() 56 | print("mean of theta: {:.3f}".format(theta_mean)) 57 | ``` 58 | 59 | And using PyStan 60 | ``` 61 | coin_dat = {'x': np.array([1,0,1,0,1,0,0,0,0,1])} 62 | fit = pystan.stan(model_code=str(coin), data=coin_dat) 63 | theta_mean = fit.extract(permuted=True)['theta'].mean() 64 | print("mean of theta: {:.3f}".format(theta_mean)) 65 | ``` -------------------------------------------------------------------------------- /notebooks/coin.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 7, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import yaps\n", 10 | "from yaps.lib import *\n", 11 | "import numpy as np\n", 12 | "from matplotlib import pyplot as plt\n", 13 | "import logging\n", 14 | "logging.getLogger('pycmdstan.model').setLevel(logging.CRITICAL)" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 8, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "@yaps.model\n", 24 | "def coin(x: int(lower=0, upper=1)[10]):\n", 25 | " theta: real(lower=0, upper=1) <~ uniform(0, 1)\n", 26 | " for i in range(1,11):\n", 27 | " x[i] <~ bernoulli(theta)" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 9, 33 | "metadata": { 34 | "scrolled": true 35 | }, 36 | "outputs": [ 37 | { 38 | "data": { 39 | "image/svg+xml": [ 40 | "\n", 41 | "\n", 43 | "\n", 45 | "\n", 46 | "\n", 48 | "\n", 49 | "%3\n", 50 | "\n", 51 | "\n", 52 | "\n", 53 | "x\n", 54 | "\n", 55 | "x\n", 56 | "\n", 57 | "\n", 58 | "\n", 59 | "theta\n", 60 | "\n", 61 | "theta\n", 62 | "\n", 63 | "\n", 64 | "\n", 65 | "theta->x\n", 66 | "\n", 67 | "\n", 68 | "\n", 69 | "\n", 70 | "\n" 71 | ], 72 | "text/plain": [ 73 | "" 74 | ] 75 | }, 76 | "execution_count": 9, 77 | "metadata": {}, 78 | "output_type": "execute_result" 79 | } 80 | ], 81 | "source": [ 82 | "coin.graph" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 10, 88 | "metadata": {}, 89 | "outputs": [ 90 | { 91 | "name": "stdout", 92 | "output_type": "stream", 93 | "text": [ 94 | "data {\n", 95 | " int x[10];\n", 96 | "}\n", 97 | "parameters {\n", 98 | " real theta;\n", 99 | "}\n", 100 | "model {\n", 101 | " theta ~ uniform(0,1);\n", 102 | " for (i in 1:11 - 1)\n", 103 | " x[i] ~ bernoulli(theta);\n", 104 | "}\n", 105 | "\n" 106 | ] 107 | } 108 | ], 109 | "source": [ 110 | "print(coin)" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": 11, 116 | "metadata": {}, 117 | "outputs": [ 118 | { 119 | "name": "stderr", 120 | "output_type": "stream", 121 | "text": [ 122 | "INFO:filelock:Lock 4430624024 acquired on /Users/baudart/.cache/pycmdstan/model-796d8029.lock\n", 123 | "INFO:filelock:Lock 4430624024 released on /Users/baudart/.cache/pycmdstan/model-796d8029.lock\n" 124 | ] 125 | } 126 | ], 127 | "source": [ 128 | "flips = np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 1])\n", 129 | "coin_obs = coin(x=flips)\n", 130 | "coin_obs.sample(data=coin_obs.data, random_='seed=42')" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 12, 136 | "metadata": {}, 137 | "outputs": [ 138 | { 139 | "name": "stdout", 140 | "output_type": "stream", 141 | "text": [ 142 | "mean of theta: 0.254\n" 143 | ] 144 | }, 145 | { 146 | "data": { 147 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXoAAAD8CAYAAAB5Pm/hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4wLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvqOYd8AAAD5JJREFUeJzt3X+M5Hddx/Hni56AINhfW1Lbxi3mAAvBFNemSkIqJbFQbGss5hrFA4sXtAIKiT3EpEZDPMSAGBFztsiRIKVWTKsFtJQ2BGOL21Ja2lI4ytkere3yo6AQKYW3f+y3Ot3u7czOd2Zn98PzkVz2+/3OZ+b76rdzr/3ed77f76SqkCS163GzDiBJmi6LXpIaZ9FLUuMseklqnEUvSY2z6CWpcRa9JDXOopekxln0ktS4bbMOAHD00UfX/Pz8rGNI0pZy4403frmq5oaN2xRFPz8/z+Li4qxjSNKWkuQ/RhnnoRtJapxFL0mNs+glqXEWvSQ1zqKXpMZZ9JLUOItekho3tOiTvDvJA0k+M7DsrUk+m+SWJP+Q5PCBx96YZH+SO5P83LSCS5JGM8oe/XuAM1Ysuxp4TlU9F/gc8EaAJCcBO4Bnd8/5yySHTSytJGndhl4ZW1UfTzK/Ytm/DMxeD5zbTZ8NXFpV3wa+mGQ/cArwbxNJq5mb333V2M89sOfMCSaRNKpJHKP/NeDD3fRxwD0Djx3slj1Gkl1JFpMsLi0tTSCGJGk1vYo+yZuAh4H3PbJolWG12nOram9VLVTVwtzc0HvySJLGNPZNzZLsBF4KnF5Vj5T5QeCEgWHHA/eOH0+S1NdYe/RJzgAuBM6qqm8NPHQlsCPJE5KcCGwHPtk/piRpXEP36JO8HzgNODrJQeAils+yeQJwdRKA66vq1VV1W5LLgNtZPqRzQVV9d1rhJUnDjXLWzXmrLL5kjfFvBt7cJ5QkaXK8MlaSGrcpvmFKG6vPufCSth736CWpcRa9JDXOopekxln0ktQ4i16SGmfRS1LjLHpJapxFL0mNs+glqXEWvSQ1zqKXpMZZ9JLUOItekhpn0UtS4yx6SWqc96OfkT73hD+w58wJJpHUOvfoJalxFr0kNc6il6TGWfSS1DiLXpIaZ9FLUuMseklq3NCiT/LuJA8k+czAsiOTXJ3k893PI7rlSfLnSfYnuSXJ86YZXpI03Ch79O8BzlixbDdwTVVtB67p5gFeDGzv/uwC3jWZmJKkcQ0t+qr6OPDVFYvPBvZ10/uAcwaWv7eWXQ8cnuTYSYWVJK3fuMfon1ZV9wF0P4/plh8H3DMw7mC3TJI0I5P+MDarLKtVBya7kiwmWVxaWppwDEnSI8Yt+vsfOSTT/XygW34QOGFg3PHAvau9QFXtraqFqlqYm5sbM4YkaZhxi/5KYGc3vRO4YmD5r3Zn35wKfP2RQzySpNkYepviJO8HTgOOTnIQuAjYA1yW5HzgbuBl3fAPAS8B9gPfAl45hcySpHUYWvRVdd4hHjp9lbEFXNA3lCRpcvzikS2oz5eWSPr+4y0QJKlxFr0kNc6il6TGWfSS1Dg/jNWW0OcD6AN7zpxgEmnrcY9ekhpn0UtS4yx6SWqcRS9JjbPoJalxFr0kNc6il6TGWfSS1DiLXpIaZ9FLUuMseklqnEUvSY2z6CWpcd69UhvGr0CUZsM9eklqnEUvSY2z6CWpcRa9JDXOopekxvU66ybJ7wCvAgq4FXglcCxwKXAkcBPw8qp6qGdOaWx9z/bxO2e11Y29R5/kOOC1wEJVPQc4DNgBvAV4e1VtB74GnD+JoJKk8fQ9dLMN+MEk24AnAfcBLwQu7x7fB5zTcx2SpB7GLvqq+hLwp8DdLBf814EbgQer6uFu2EHguL4hJUnj63Po5gjgbOBE4EeAJwMvXmVoHeL5u5IsJllcWloaN4YkaYg+h25eBHyxqpaq6jvAB4GfAQ7vDuUAHA/cu9qTq2pvVS1U1cLc3FyPGJKktfQp+ruBU5M8KUmA04HbgWuBc7sxO4Er+kWUJPXR5xj9DSx/6HoTy6dWPg7YC1wIvD7JfuAo4JIJ5JQkjanXefRVdRFw0YrFdwGn9HldSdLkeGWsJDXOopekxln0ktQ4i16SGmfRS1LjLHpJapxFL0mNs+glqXEWvSQ1zqKXpMZZ9JLUOItekhpn0UtS4yx6SWqcRS9JjbPoJalxFr0kNc6il6TGWfSS1DiLXpIaZ9FLUuMseklq3LZZB9jK5ndfNesIkjSUe/SS1DiLXpIa16vokxye5PIkn01yR5KfTnJkkquTfL77ecSkwkqS1q/vHv07gI9U1bOAnwDuAHYD11TVduCabl6SNCNjF32SpwIvAC4BqKqHqupB4GxgXzdsH3BO35CSpPH12aN/OrAE/E2STyW5OMmTgadV1X0A3c9jJpBTkjSmPkW/DXge8K6qOhn4Jus4TJNkV5LFJItLS0s9YkiS1tKn6A8CB6vqhm7+cpaL//4kxwJ0Px9Y7clVtbeqFqpqYW5urkcMSdJaxi76qvpP4J4kz+wWnQ7cDlwJ7OyW7QSu6JVQktRL3ytjXwO8L8njgbuAV7L8y+OyJOcDdwMv67kOSVIPvYq+qm4GFlZ56PQ+rytJmhyvjJWkxln0ktQ4i16SGmfRS1LjLHpJapxFL0mNs+glqXEWvSQ1zqKXpMZZ9JLUOItekhpn0UtS4yx6SWqcRS9JjbPoJalxFr0kNa7vN0xtefO7r5p1BEmaKvfoJalxFr0kNc6il6TGWfSS1DiLXpIaZ9FLUuMseklqnEUvSY2z6CWpcb2vjE1yGLAIfKmqXprkROBS4EjgJuDlVfVQ3/VIW1GfK68P7Dlzgkn0/WwSe/SvA+4YmH8L8Paq2g58DTh/AuuQJI2pV9EnOR44E7i4mw/wQuDybsg+4Jw+65Ak9dN3j/7PgN8FvtfNHwU8WFUPd/MHgeNWe2KSXUkWkywuLS31jCFJOpSxiz7JS4EHqurGwcWrDK3Vnl9Ve6tqoaoW5ubmxo0hSRqiz4exzwfOSvIS4InAU1newz88ybZur/544N7+MaXZ8VbW2urG3qOvqjdW1fFVNQ/sAD5WVb8MXAuc2w3bCVzRO6UkaWzTOI/+QuD1SfazfMz+kimsQ5I0ool8w1RVXQdc103fBZwyideVJPXnlbGS1DiLXpIaZ9FLUuMseklqnEUvSY2z6CWpcRa9JDXOopekxln0ktQ4i16SGmfRS1LjLHpJapxFL0mNs+glqXEWvSQ1zqKXpMZZ9JLUOItekhpn0UtS4yx6SWrcRL4cXNLkze++auznHthz5gSTaKtzj16SGmfRS1LjLHpJapxFL0mNG7vok5yQ5NokdyS5LcnruuVHJrk6yee7n0dMLq4kab367NE/DLyhqn4cOBW4IMlJwG7gmqraDlzTzUuSZmTs0yur6j7gvm76v5LcARwHnA2c1g3bB1wHXNgr5Rr6nIIm6bH6/p3y1M7NZyLH6JPMAycDNwBP634JPPLL4JhJrEOSNJ7eRZ/kh4C/B367qr6xjuftSrKYZHFpaalvDEnSIfQq+iQ/wHLJv6+qPtgtvj/Jsd3jxwIPrPbcqtpbVQtVtTA3N9cnhiRpDX3OuglwCXBHVb1t4KErgZ3d9E7givHjSZL66nOvm+cDLwduTXJzt+z3gD3AZUnOB+4GXtYvoqT18iQFDepz1s0ngBzi4dPHfV1J0mR5ZawkNc6il6TGWfSS1DiLXpIaZ9FLUuMseklqnEUvSY2z6CWpcRa9JDXOopekxvW5140kPUaf++z4pSXT4R69JDXOopekxln0ktQ4i16SGmfRS1LjLHpJapxFL0mNs+glqXEWvSQ1zqKXpMZZ9JLUOO91I0k9bfb7+7hHL0mNs+glqXFTO3ST5AzgHcBhwMVVtWda65LUhj6HQPpo/fbIU9mjT3IY8E7gxcBJwHlJTprGuiRJa5vWoZtTgP1VdVdVPQRcCpw9pXVJktYwraI/DrhnYP5gt0yStMGmdYw+qyyrRw1IdgG7utn/TnLnKs85GvjyhLNN01bLC1svs3mnb6tl7p03b5lQktE8Km/Pdf/oKIOmVfQHgRMG5o8H7h0cUFV7gb1rvUiSxapamHy86dhqeWHrZTbv9G21zOYdblqHbv4d2J7kxCSPB3YAV05pXZKkNUxlj76qHk7yW8A/s3x65bur6rZprEuStLapnUdfVR8CPtTzZdY8tLMJbbW8sPUym3f6tlpm8w6Rqho+SpK0ZXkLBElq3KYo+iRnJLkzyf4ku1d5/AlJPtA9fkOS+Y1P+ag8w/K+IMlNSR5Ocu4sMq7IMyzv65PcnuSWJNckGemUrWkaIfOrk9ya5OYkn5j1ldfD8g6MOzdJJZnpWSIjbN9XJFnqtu/NSV41i5wrMg3dxkl+qXsv35bkbzc644osw7bx2we27+eSPDi1MFU10z8sf1j7BeDpwOOBTwMnrRjzm8BfddM7gA9s8rzzwHOB9wLnboHt+7PAk7rp35jl9l1H5qcOTJ8FfGQz5+3GPQX4OHA9sLCZ8wKvAP5ilu+DMTJvBz4FHNHNH7OZ864Y/xqWT1qZSp7NsEc/yu0Szgb2ddOXA6cnWe2irI0wNG9VHaiqW4DvzSLgCqPkvbaqvtXNXs/ydQ+zNErmbwzMPpkVF+RtsFFv+fFHwJ8A/7OR4VaxFW9RMkrmXwfeWVVfA6iqBzY446D1buPzgPdPK8xmKPpRbpfwf2Oq6mHg68BRG5Lusbba7R3Wm/d84MNTTTTcSJmTXJDkCyyX52s3KNtqhuZNcjJwQlX900YGO4RR3xO/2B3OuzzJCas8vpFGyfwM4BlJ/jXJ9d0ddGdl5L933aHSE4GPTSvMZij6obdLGHHMRtlMWUYxct4kvwIsAG+daqLhRspcVe+sqh8DLgR+f+qpDm3NvEkeB7wdeMOGJVrbKNv3H4H5qnou8FH+/1/UszJK5m0sH745jeU95IuTHD7lXIeynp7YAVxeVd+dVpjNUPRDb5cwOCbJNuCHga9uSLrHGiXvZjJS3iQvAt4EnFVV396gbIey3m18KXDOVBOtbVjepwDPAa5LcgA4Fbhyhh/IjnKLkq8MvA/+GvjJDcp2KKP2xBVV9Z2q+iJwJ8vFPwvreQ/vYIqHbYBN8WHsNuAulv/p8siHFs9eMeYCHv1h7GWbOe/A2Pcw+w9jR9m+J7P8wdH2Wb8f1pF5+8D0zwOLmznvivHXMdsPY0fZvscOTP8CcP0WeE+cAezrpo9m+dDJUZs1bzfumcABumuappZnlv/zBv5jXwJ8riubN3XL/pDlvUuAJwJ/B+wHPgk8fZPn/SmWf6N/E/gKcNsmz/tR4H7g5u7PlVvgPfEO4LYu77VrFetmyLti7EyLfsTt+8fd9v10t32ftQXeEwHeBtwO3Ars2Mx5u/k/APZMO4tXxkpS4zbDMXpJ0hRZ9JLUOItekhpn0UtS4yx6SWqcRS9JjbPoJalxFr0kNe5/AQ/hmNnvbUENAAAAAElFTkSuQmCC\n", 148 | "text/plain": [ 149 | "
" 150 | ] 151 | }, 152 | "metadata": { 153 | "needs_background": "light" 154 | }, 155 | "output_type": "display_data" 156 | } 157 | ], 158 | "source": [ 159 | "theta = coin_obs.posterior.theta\n", 160 | "plt.hist(theta, bins=20)\n", 161 | "print('mean of theta: {:.3f}'.format(theta.mean()))" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": null, 167 | "metadata": {}, 168 | "outputs": [], 169 | "source": [] 170 | } 171 | ], 172 | "metadata": { 173 | "kernelspec": { 174 | "display_name": "Python 3", 175 | "language": "python", 176 | "name": "python3" 177 | }, 178 | "language_info": { 179 | "codemirror_mode": { 180 | "name": "ipython", 181 | "version": 3 182 | }, 183 | "file_extension": ".py", 184 | "mimetype": "text/x-python", 185 | "name": "python", 186 | "nbconvert_exporter": "python", 187 | "pygments_lexer": "ipython3", 188 | "version": "3.6.6" 189 | } 190 | }, 191 | "nbformat": 4, 192 | "nbformat_minor": 2 193 | } 194 | -------------------------------------------------------------------------------- /notebooks/error_reporting.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import yaps\n", 10 | "from yaps.lib import *\n", 11 | "import numpy as np\n", 12 | "import logging\n", 13 | "logging.getLogger('pycmdstan.model').setLevel(logging.CRITICAL)" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 2, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "@yaps.model\n", 23 | "def coin(x: int(lower=0, upper=1)[10]):\n", 24 | " for i in range(1,11):\n", 25 | " x[i] <~ bernoulli(theta)" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 3, 31 | "metadata": { 32 | "scrolled": true 33 | }, 34 | "outputs": [ 35 | { 36 | "name": "stderr", 37 | "output_type": "stream", 38 | "text": [ 39 | "INFO:filelock:Lock 4638481320 acquired on /Users/baudart/.cache/pycmdstan/model-3aed19a9.lock\n", 40 | "INFO:filelock:Lock 4638481320 released on /Users/baudart/.cache/pycmdstan/model-3aed19a9.lock\n" 41 | ] 42 | }, 43 | { 44 | "ename": "ValueError", 45 | "evalue": "Model name=model_3aed19a9_model\nInput file=/Users/baudart/.cache/pycmdstan/model-3aed19a9.stan\nOutput file=/Users/baudart/.cache/pycmdstan/model-3aed19a9.hpp\nSYNTAX ERROR, MESSAGE(S) FROM PARSER:\n\nvariable \"theta\" does not exist.\n error in '/Users/baudart/.cache/pycmdstan/model-3aed19a9.stan' at line 4, column 27\n-------------------------------------------------\n 1: @yaps.model\n 2: def coin(x: int(lower=0, upper=1)[10]):\n 3: for i in range(1,11):\n 4: x[i] <~ bernoulli(theta)\n ^\n-------------------------------------------------\n\n\n\nmake: *** [/Users/baudart/.cache/pycmdstan/model-3aed19a9.hpp] Error 253\n", 46 | "output_type": "error", 47 | "traceback": [ 48 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 49 | "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", 50 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/yaps/decorator.py\u001b[0m in \u001b[0;36mmethod\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mredirect_stdout\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 50\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcmdstan_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 51\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mposterior\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mStruct\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcsv\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 51 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/pycmdstan/model.py\u001b[0m in \u001b[0;36msample\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 143\u001b[0m \"\"\"\n\u001b[0;32m--> 144\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'sample'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 145\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", 52 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/pycmdstan/model.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(self, method, chains, wait, seed, **kwargs)\u001b[0m\n\u001b[1;32m 165\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mrng\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandom_integers\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m99999\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 166\u001b[0;31m **kwargs) for _ in range(chains)\n\u001b[0m\u001b[1;32m 167\u001b[0m ]\n", 53 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/pycmdstan/model.py\u001b[0m in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 165\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mrng\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandom_integers\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m99999\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 166\u001b[0;31m **kwargs) for _ in range(chains)\n\u001b[0m\u001b[1;32m 167\u001b[0m ]\n", 54 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/pycmdstan/model.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, model, method, data, id, log_lik, start, wait, tmp_dir, **method_args)\u001b[0m\n\u001b[1;32m 199\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mstart\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 200\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstart\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 201\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", 55 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/pycmdstan/model.py\u001b[0m in \u001b[0;36mstart\u001b[0;34m(self, wait)\u001b[0m\n\u001b[1;32m 246\u001b[0m self.proc = subprocess.Popen(\n\u001b[0;32m--> 247\u001b[0;31m self.cmd, stdout=self._output_fd, stderr=subprocess.STDOUT)\n\u001b[0m\u001b[1;32m 248\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mwait\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 56 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, encoding, errors)\u001b[0m\n\u001b[1;32m 708\u001b[0m \u001b[0merrread\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merrwrite\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 709\u001b[0;31m restore_signals, start_new_session)\n\u001b[0m\u001b[1;32m 710\u001b[0m \u001b[0;32mexcept\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 57 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36m_execute_child\u001b[0;34m(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, start_new_session)\u001b[0m\n\u001b[1;32m 1343\u001b[0m \u001b[0merr_msg\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;34m': '\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mrepr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr_filename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1344\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mchild_exception_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrno_num\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr_msg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr_filename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1345\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mchild_exception_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr_msg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 58 | "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '/Users/baudart/.cache/pycmdstan/model-3aed19a9': '/Users/baudart/.cache/pycmdstan/model-3aed19a9'", 59 | "\nDuring handling of the above exception, another exception occurred:\n", 60 | "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", 61 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mflips\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mcoin_obs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mflips\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mcoin_obs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msample\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcoin_obs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrandom_\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'seed=42'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 62 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/yaps/decorator.py\u001b[0m in \u001b[0;36mmethod\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 53\u001b[0m \u001b[0me\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmap_valueerror\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgetvalue\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 54\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__traceback__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__traceback__\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 55\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 56\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mmethod\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 57\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 63 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/yaps/decorator.py\u001b[0m in \u001b[0;36mmethod\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 48\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mredirect_stdout\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 50\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcmdstan_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 51\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mposterior\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mStruct\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcsv\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 52\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 64 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/pycmdstan/model.py\u001b[0m in \u001b[0;36msample\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 142\u001b[0m \"\"\"Run the model with the sample (NUTS/HMC) method.\n\u001b[1;32m 143\u001b[0m \"\"\"\n\u001b[0;32m--> 144\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'sample'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 145\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 146\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mvariational\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 65 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/pycmdstan/model.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(self, method, chains, wait, seed, **kwargs)\u001b[0m\n\u001b[1;32m 164\u001b[0m \u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 165\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mrng\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandom_integers\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m99999\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 166\u001b[0;31m **kwargs) for _ in range(chains)\n\u001b[0m\u001b[1;32m 167\u001b[0m ]\n\u001b[1;32m 168\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mruns\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 66 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/pycmdstan/model.py\u001b[0m in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 164\u001b[0m \u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 165\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mrng\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandom_integers\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m99999\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 166\u001b[0;31m **kwargs) for _ in range(chains)\n\u001b[0m\u001b[1;32m 167\u001b[0m ]\n\u001b[1;32m 168\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mruns\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 67 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/pycmdstan/model.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, model, method, data, id, log_lik, start, wait, tmp_dir, **method_args)\u001b[0m\n\u001b[1;32m 198\u001b[0m \u001b[0mio\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrdump\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata_R_fname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 199\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mstart\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 200\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstart\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 201\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 202\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__del__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 68 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/site-packages/pycmdstan/model.py\u001b[0m in \u001b[0;36mstart\u001b[0;34m(self, wait)\u001b[0m\n\u001b[1;32m 245\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_output_fd\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moutput_fname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'w'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 246\u001b[0m self.proc = subprocess.Popen(\n\u001b[0;32m--> 247\u001b[0;31m self.cmd, stdout=self._output_fd, stderr=subprocess.STDOUT)\n\u001b[0m\u001b[1;32m 248\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mwait\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 249\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 69 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, encoding, errors)\u001b[0m\n\u001b[1;32m 707\u001b[0m \u001b[0mc2pread\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc2pwrite\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 708\u001b[0m \u001b[0merrread\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merrwrite\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 709\u001b[0;31m restore_signals, start_new_session)\n\u001b[0m\u001b[1;32m 710\u001b[0m \u001b[0;32mexcept\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 711\u001b[0m \u001b[0;31m# Cleanup if the child failed starting.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 70 | "\u001b[0;32m/usr/local/anaconda3/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36m_execute_child\u001b[0;34m(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, start_new_session)\u001b[0m\n\u001b[1;32m 1342\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merrno_num\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0merrno\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mENOENT\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1343\u001b[0m \u001b[0merr_msg\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;34m': '\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mrepr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr_filename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1344\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mchild_exception_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merrno_num\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr_msg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr_filename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1345\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mchild_exception_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr_msg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1346\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", 71 | "\u001b[0;31mValueError\u001b[0m: Model name=model_3aed19a9_model\nInput file=/Users/baudart/.cache/pycmdstan/model-3aed19a9.stan\nOutput file=/Users/baudart/.cache/pycmdstan/model-3aed19a9.hpp\nSYNTAX ERROR, MESSAGE(S) FROM PARSER:\n\nvariable \"theta\" does not exist.\n error in '/Users/baudart/.cache/pycmdstan/model-3aed19a9.stan' at line 4, column 27\n-------------------------------------------------\n 1: @yaps.model\n 2: def coin(x: int(lower=0, upper=1)[10]):\n 3: for i in range(1,11):\n 4: x[i] <~ bernoulli(theta)\n ^\n-------------------------------------------------\n\n\n\nmake: *** [/Users/baudart/.cache/pycmdstan/model-3aed19a9.hpp] Error 253\n" 72 | ] 73 | } 74 | ], 75 | "source": [ 76 | "flips = np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 1])\n", 77 | "coin_obs = coin(x=flips)\n", 78 | "coin_obs.sample(data=coin_obs.data, random_='seed=42')" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": null, 84 | "metadata": {}, 85 | "outputs": [], 86 | "source": [] 87 | } 88 | ], 89 | "metadata": { 90 | "kernelspec": { 91 | "display_name": "Python 3", 92 | "language": "python", 93 | "name": "python3" 94 | }, 95 | "language_info": { 96 | "codemirror_mode": { 97 | "name": "ipython", 98 | "version": 3 99 | }, 100 | "file_extension": ".py", 101 | "mimetype": "text/x-python", 102 | "name": "python", 103 | "nbconvert_exporter": "python", 104 | "pygments_lexer": "ipython3", 105 | "version": "3.6.6" 106 | } 107 | }, 108 | "nbformat": 4, 109 | "nbformat_minor": 2 110 | } 111 | -------------------------------------------------------------------------------- /notebooks/slicstan.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from yaps.lib import int, real, uniform, bernoulli\n", 10 | "import yaps as yaps" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 2, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "@yaps.model\n", 20 | "def slicstan(N: int[10], y: real(lower=0, upper=1)[10]):\n", 21 | " tau: real is gamma(0.1, 0.1)\n", 22 | " mu: real is normal(0, 1)\n", 23 | " with transformed_parameters:\n", 24 | " sigma: real = pow(tau, (5 % 2))\n", 25 | " y is normal(mu, sigma)\n", 26 | " with generated_quantities:\n", 27 | " v: real = pow(sigma, 2)" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 3, 33 | "metadata": {}, 34 | "outputs": [ 35 | { 36 | "name": "stdout", 37 | "output_type": "stream", 38 | "text": [ 39 | "data {\n", 40 | " int N[10];\n", 41 | " real y[10];\n", 42 | "}\n", 43 | "parameters {\n", 44 | " real tau;\n", 45 | " real mu;\n", 46 | "}\n", 47 | "transformed parameters {\n", 48 | " real sigma = pow(tau,5 % 2);\n", 49 | "}\n", 50 | "model {\n", 51 | " tau ~ gamma(0.1,0.1);\n", 52 | " mu ~ normal(0,1);\n", 53 | " y ~ normal(mu,sigma);\n", 54 | "}\n", 55 | "generated quantities {\n", 56 | " real v = pow(sigma,2);\n", 57 | "}\n", 58 | "\n" 59 | ] 60 | } 61 | ], 62 | "source": [ 63 | "print(slicstan)" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": null, 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [] 72 | } 73 | ], 74 | "metadata": { 75 | "kernelspec": { 76 | "display_name": "Python 3", 77 | "language": "python", 78 | "name": "python3" 79 | }, 80 | "language_info": { 81 | "codemirror_mode": { 82 | "name": "ipython", 83 | "version": 3 84 | }, 85 | "file_extension": ".py", 86 | "mimetype": "text/x-python", 87 | "name": "python", 88 | "nbconvert_exporter": "python", 89 | "pygments_lexer": "ipython3", 90 | "version": "3.6.6" 91 | } 92 | }, 93 | "nbformat": 4, 94 | "nbformat_minor": 2 95 | } 96 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 IBM Corporation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from setuptools import setup 16 | import os 17 | import sys 18 | 19 | with open("README.md", "r") as fh: 20 | long_description = fh.read() 21 | 22 | setup( 23 | name='yaps', 24 | version='0.1.4', 25 | author="Guillaume Baudart, Martin Hirzel, Kiran Kate, Louis Mandel, Avraham Shinnar", 26 | description="A surface language for programming Stan models using python syntax", 27 | long_description=long_description, 28 | long_description_content_type="text/markdown", 29 | url="https://github.com/IBM/yaps", 30 | packages=['yaps', ], 31 | license='Apache License 2.0', 32 | install_requires=[ 33 | 'astor', 'graphviz', 'antlr4-python3-runtime', 'pycmdstan' 34 | ], 35 | entry_points={ 36 | 'console_scripts': ['stan2yaps=yaps.stan2yaps:main', 37 | 'yaps-roundtrip=yaps.roundtrip:main'], 38 | } 39 | ) 40 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/yaps/39b5833ff61c8d7f0f60bc763b07205dd7058aef/tests/__init__.py -------------------------------------------------------------------------------- /tests/runtime/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/yaps/39b5833ff61c8d7f0f60bc763b07205dd7058aef/tests/runtime/__init__.py -------------------------------------------------------------------------------- /tests/runtime/test_coin.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_coin(): 6 | stan_code = """ 7 | data { 8 | int x[10]; 9 | } 10 | parameters { 11 | real theta; 12 | } 13 | model { 14 | theta ~ uniform(0.1,1.0); 15 | for (i in 1:10){ 16 | x[i] ~ bernoulli(theta); 17 | } 18 | } 19 | """ 20 | 21 | data = {'x': np.array([0, 1, 1, 0, 1, 1, 0, 0, 0, 1])} 22 | compare_models(stan_code, data) 23 | 24 | 25 | if __name__ == "__main__": 26 | test_coin() 27 | -------------------------------------------------------------------------------- /tests/runtime/test_gaussian_process.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_gaussian_process(): 6 | stan_code = """ 7 | data { 8 | int N; 9 | real x[N]; 10 | } 11 | transformed data { 12 | matrix[N, N] K; 13 | vector[N] mu = rep_vector(0, N); 14 | for (i in 1:(N - 1)) { 15 | K[i, i] = 1 + 0.1; 16 | for (j in (i + 1):N) { 17 | K[i, j] = exp(-0.5 * square(x[i] - x[j])); 18 | K[j, i] = K[i, j]; 19 | } 20 | } 21 | K[N, N] = 1 + 0.1; 22 | } 23 | parameters { 24 | vector[N] y; 25 | } 26 | model { 27 | y ~ multi_normal(mu, K); 28 | } 29 | """ 30 | 31 | num_samples = 6 32 | X = np.array([5, 6, 1, 0, 9, 10]) 33 | 34 | data = {'N': num_samples, 35 | 'x': X} 36 | 37 | compare_models(stan_code, data) 38 | 39 | 40 | if __name__ == "__main__": 41 | test_gaussian_process() 42 | -------------------------------------------------------------------------------- /tests/runtime/test_gradient_warn.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_gradient_warn(): 6 | stan_code = """ 7 | data { 8 | int N; 9 | vector[N] p; 10 | int Ngrps; 11 | int grp_index[N]; 12 | } 13 | parameters { 14 | vector[Ngrps] sigmaGrp; 15 | vector[Ngrps] muGrp; 16 | } 17 | 18 | model { 19 | int grpi; 20 | for (i in 1:N){ 21 | grpi <- grp_index[i]; 22 | p[i] ~ logistic(muGrp[grpi], sigmaGrp[grpi]); 23 | }; 24 | } 25 | """ 26 | 27 | num_samples = 10 28 | X = np.array([63.1, 108.3, 1.0, 46.0, 22.9, 14.8, 28.8, 52.5, 60.1, 81.3]) 29 | 30 | data = {'N': num_samples, 31 | 'p': X, 32 | 'Ngrps': 5, 33 | 'grp_index': np.array([1, 1, 1, 1, 1, 1, 2, 3, 4, 5])} 34 | 35 | compare_models(stan_code, data) 36 | 37 | 38 | if __name__ == "__main__": 39 | test_gradient_warn() 40 | -------------------------------------------------------------------------------- /tests/runtime/test_kmeans.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_kmeans(): 6 | stan_code = """ 7 | data { 8 | int N; // number of data points 9 | int D; // number of dimensions 10 | int K; // number of clusters 11 | vector[D] y[N]; // observations 12 | } 13 | transformed data { 14 | real neg_log_K; 15 | neg_log_K = -log(K); 16 | } 17 | parameters { 18 | vector[D] mu[K]; // cluster means 19 | } 20 | transformed parameters { 21 | real soft_z[N, K]; // log unnormalized clusters 22 | for (n in 1:N) 23 | for (k in 1:K) 24 | soft_z[n, k] = neg_log_K 25 | - 0.5 * dot_self(mu[k] - y[n]); 26 | } 27 | model { 28 | // prior 29 | for (k in 1:K) 30 | mu[k] ~ normal(0, 1); 31 | // likelihood 32 | for (n in 1:N) 33 | target += log_sum_exp(soft_z[n]); 34 | } 35 | """ 36 | 37 | num_samples = 6 38 | num_features = 2 39 | X = np.array([[1, 2], [1, 4], [1, 0], [4, 2], [4, 4], [4, 0]]) 40 | num_clusters = 2 41 | 42 | data = {'N': num_samples, 43 | 'D': num_features, 44 | 'K': num_clusters, 45 | 'y': X} 46 | 47 | compare_models(stan_code, data) 48 | 49 | 50 | if __name__ == "__main__": 51 | test_kmeans() 52 | -------------------------------------------------------------------------------- /tests/runtime/test_logistic.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_logistic(): 6 | stan_code = """ 7 | data { 8 | int N; // number of items 9 | int M; // number of predictors 10 | int y[N]; // outcomes 11 | row_vector[M] x[N]; // predictors 12 | } 13 | parameters { 14 | vector[M] beta; // coefficients 15 | } 16 | model { 17 | for (m in 1:M) 18 | beta[m] ~ cauchy(0.0, 2.5); 19 | 20 | for (n in 1:N) 21 | y[n] ~ bernoulli(inv_logit(x[n] * beta)); 22 | } 23 | """ 24 | 25 | num_samples = 7 26 | num_features = 2 27 | #X = np.array([[1, 1], [1, 2], [2, 2], [2, 3]]) 28 | X = np.array([[1, 1.329799263], [1, 1.272429321], [1, -1.539950042], 29 | [1, -0.928567035], [1, -0.294720447], [1, -0.005767173], [1, 2.404653389]]) 30 | # y = 1 * x_0 + 2 * x_1 + 3 31 | y = np.array([0, 1, 1, 1, 1, 1, 1]) 32 | data = {'N': num_samples, 33 | 'M': num_features, 34 | 'x': X, 35 | 'y': y} 36 | 37 | compare_models(stan_code, data) 38 | 39 | 40 | if __name__ == "__main__": 41 | test_logistic() 42 | -------------------------------------------------------------------------------- /tests/runtime/test_missing_data.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_missing_data(): 6 | stan_code = """ 7 | data { 8 | int N_obs; 9 | int N_mis; 10 | real y_obs[N_obs]; 11 | } 12 | parameters { 13 | real mu; 14 | real sigma; 15 | real y_mis[N_mis]; 16 | } 17 | model { 18 | y_obs ~ normal(mu, sigma); 19 | y_mis ~ normal(mu, sigma); 20 | } 21 | """ 22 | 23 | num_samples = 6 24 | X = np.array([5, 6, 1, 0, 9, 10]) 25 | 26 | data = {'N_obs': num_samples, 27 | 'N_mis': 2, 28 | 'y_obs': X} 29 | 30 | compare_models(stan_code, data) 31 | 32 | 33 | if __name__ == "__main__": 34 | test_missing_data() 35 | -------------------------------------------------------------------------------- /tests/runtime/test_regression.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_regression(): 6 | stan_code = """ 7 | data { 8 | int N; 9 | vector[N] x; 10 | vector[N] y; 11 | } 12 | parameters { 13 | real alpha; 14 | real beta; 15 | real sigma; 16 | } 17 | model { 18 | y ~ normal(alpha + beta * x, sigma); 19 | } 20 | """ 21 | 22 | num_samples = 100 23 | X = np.arange(num_samples) 24 | y = np.arange(num_samples) 25 | 26 | data = {'N': num_samples, 27 | 'x': X, 28 | 'y': y} 29 | 30 | compare_models(stan_code, data) 31 | -------------------------------------------------------------------------------- /tests/runtime/test_regression_matrix.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_regression_matrix(): 6 | stan_code = """ 7 | data { 8 | int N; 9 | int K; 10 | matrix[N, K] x; 11 | vector[N] y; 12 | } 13 | parameters { 14 | real alpha; 15 | vector[K] beta; 16 | real sigma; 17 | } 18 | model { 19 | y ~ normal(x * beta + alpha, sigma); 20 | } 21 | """ 22 | 23 | num_samples = 100 24 | num_features = 2 25 | #X = np.array([[1, 1], [1, 2], [2, 2], [2, 3]]) 26 | X = np.random.randint(5, size=(100, 2)) 27 | # y = 1 * x_0 + 2 * x_1 + 3 28 | y = np.dot(X, np.array([1, 2])) + 3 29 | 30 | data = {'N': num_samples, 31 | 'K': num_features, 32 | 'x': X, 33 | 'y': y} 34 | 35 | compare_models(stan_code, data) 36 | 37 | # if matplotlib is installed (optional, not required), a visual summary and 38 | # traceplot are available 39 | # print(fit_stan) 40 | #import matplotlib.pyplot as plt 41 | # fit.plot() 42 | # plt.show() 43 | 44 | 45 | test_regression_matrix() 46 | -------------------------------------------------------------------------------- /tests/runtime/test_row_vector_expr_terms.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_row_vector_expr_terms(): 6 | stan_code = """ 7 | functions { 8 | 9 | vector foo(int d) { 10 | vector[3] result = [10.1, 11*3.0, d]'; 11 | return result; 12 | } 13 | 14 | row_vector bar() { 15 | row_vector[2] result = [7, 8]; 16 | return result; 17 | } 18 | 19 | } 20 | data { 21 | real x; 22 | real y; 23 | } 24 | transformed data { 25 | vector[3] td_v1 = [ 21, 22, 23]'; 26 | row_vector[2] td_rv1 = [ 1, 2]; 27 | td_rv1 = [ x, y]; 28 | td_rv1 = [ x + y, x - y]; 29 | td_rv1 = [ x^2, y^2]; 30 | td_v1 = foo(1); 31 | td_rv1 = bar(); 32 | } 33 | parameters { 34 | real z; 35 | } 36 | transformed parameters { 37 | vector[3] tp_v1 = [ 41, 42, 43]'; 38 | row_vector[2] tp_rv1 = [ 1, x]; 39 | tp_v1 = foo(1); 40 | tp_v1 = [ 51, y, z]'; 41 | tp_rv1 = [ y, z]; 42 | tp_rv1 = bar(); 43 | } 44 | model { 45 | z ~ normal(0,1); 46 | } 47 | generated quantities { 48 | vector[3] gq_v1 = [1, x, y]'; 49 | row_vector[3] gq_rv1 = [1, x, y]; 50 | row_vector[3] gq_rv2 = [1, x, z]; 51 | gq_v1 = foo(1); 52 | } 53 | """ 54 | 55 | # Add Data 56 | x = 56.789 57 | y = 98.765 58 | data = {'x': x, 'y': y} 59 | 60 | compare_models(stan_code, data) 61 | 62 | 63 | if __name__ == "__main__": 64 | test_row_vector_expr_terms() 65 | -------------------------------------------------------------------------------- /tests/runtime/test_schools.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_schools(): 6 | stan_code = """ 7 | data { 8 | int J; // number of schools 9 | real y[J]; // estimated treatment effects 10 | real sigma[J]; // s.e. of effect estimates 11 | } 12 | parameters { 13 | real mu; 14 | real tau; 15 | real eta[J]; 16 | } 17 | transformed parameters { 18 | real theta[J]; 19 | for (j in 1:J) 20 | theta[j] = mu + tau * eta[j]; 21 | } 22 | model { 23 | eta ~ normal(0, 1); 24 | y ~ normal(theta, sigma); 25 | } 26 | """ 27 | 28 | schools_dat = {'J': 8, 29 | 'y': np.array([28, 8, -3, 7, -1, 1, 18, 12]), 30 | 'sigma': np.array([15, 10, 16, 11, 9, 11, 10, 18])} 31 | 32 | compare_models(stan_code, schools_dat) 33 | -------------------------------------------------------------------------------- /tests/runtime/test_squared_error.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_squared_error(): 6 | stan_code = """ 7 | data { 8 | int N; 9 | int K; 10 | vector[N] y; 11 | matrix[N,K] x; 12 | } 13 | parameters { 14 | vector[K] beta; 15 | } 16 | transformed parameters { 17 | real squared_error; 18 | squared_error = dot_self(y - x * beta); 19 | } 20 | model { 21 | target += -squared_error; 22 | } 23 | generated quantities { 24 | real sigma_squared; 25 | sigma_squared = squared_error / N; 26 | } 27 | """ 28 | 29 | num_samples = 100 30 | num_features = 2 31 | #X = np.array([[1, 1], [1, 2], [2, 2], [2, 3]]) 32 | X = np.random.randint(5, size=(100, 2)) 33 | # y = 1 * x_0 + 2 * x_1 + 3 34 | y = np.dot(X, np.array([1, 2])) + 3 35 | 36 | data = {'N': num_samples, 37 | 'K': num_features, 38 | 'x': X, 39 | 'y': y} 40 | 41 | compare_models(stan_code, data) 42 | 43 | 44 | test_squared_error() 45 | -------------------------------------------------------------------------------- /tests/runtime/test_validate_arr_expr_primitives.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_validate_arr_expr_primitives(): 6 | stan_code = """ 7 | functions { 8 | int[] f1_arr_int() { 9 | return {-1, -2}; 10 | } 11 | int[] f2_arr_int(int x) { 12 | return {-x}; 13 | } 14 | real[] f1_arr_real() { 15 | return {-1.0, -2.0}; 16 | } 17 | real[] f2_arr_real(real y) { 18 | return {-y}; 19 | } 20 | } 21 | data { 22 | int d_i1; 23 | int d_i2; 24 | int d_i3; 25 | real d_r1; 26 | real d_r2; 27 | real d_r3; 28 | } 29 | transformed data { 30 | int td_arr_int_d1_1[3] = {1, 2, 3}; 31 | int td_arr_int_d1_2[3] = {d_i1, 2, 3}; 32 | int td_arr_int_d1_3[2] = f1_arr_int(); 33 | int td_arr_int_d1_4[1] = f2_arr_int(d_i2); 34 | int td_arr_int_d2_1[1,2] = {{4, 5}}; 35 | int td_arr_int_d2_2[1,2] = {{4, d_i3}}; 36 | int td_arr_int_d2_3[2,3] = {{1,2,3},{4,5,6}}; 37 | int td_arr_int_d2_4[2,3] = { td_arr_int_d1_1, td_arr_int_d1_2 }; 38 | 39 | real td_arr_real_d1_1[3] = {1.1, 2.2, 3.3}; 40 | real td_arr_real_d1_2[3] = {d_r1, 2, 3}; 41 | real td_arr_real_d1_3[2] = f1_arr_real(); 42 | real td_arr_real_d1_4[1] = f2_arr_real(d_r2); 43 | real td_arr_real_d2_1[1,2] = {{4.4, 5.5}}; 44 | real td_arr_real_d2_2[1,2] = {{4.4, d_r2}}; 45 | 46 | print("td_arr_int_d1_1 = ", td_arr_int_d1_1); 47 | print("td_arr_int_d1_2 = ", td_arr_int_d1_2); 48 | print("td_arr_int_d1_3 = ",td_arr_int_d1_3); 49 | print("td_arr_int_d1_4 = ",td_arr_int_d1_4); 50 | print("td_arr_int_d2_1 = ",td_arr_int_d2_1); 51 | print("td_arr_int_d2_2 = ",td_arr_int_d2_2); 52 | print("td_arr_int_d2_3 = ",td_arr_int_d2_3); 53 | print("td_arr_int_d2_4 = ",td_arr_int_d2_4); 54 | print(""); 55 | print("td_arr_real_d1_1 = ",td_arr_real_d1_1); 56 | print("td_arr_real_d1_2 = ",td_arr_real_d1_2); 57 | print("td_arr_real_d1_3 = ",td_arr_real_d1_3); 58 | print("td_arr_real_d1_4 = ",td_arr_real_d1_4); 59 | print("td_arr_real_d2_1 = ",td_arr_real_d2_1); 60 | print("td_arr_real_d2_2 = ",td_arr_real_d2_2); 61 | print(""); 62 | 63 | { 64 | int loc_td_arr_int_d1_1[3] = {1, 2, 3}; 65 | int loc_td_arr_int_d1_2[3] = {d_i1, 2, 3}; 66 | int loc_td_arr_int_d1_3[2] = f1_arr_int(); 67 | int loc_td_arr_int_d1_4[1] = f2_arr_int(d_i2); 68 | int loc_td_arr_int_d2_1[1,2] = {{4, 5}}; 69 | int loc_td_arr_int_d2_2[1,2] = {{4, d_i3}}; 70 | int loc_td_arr_int_d2_3[2,3] = {{1,2,3},{4,5,6}}; 71 | int loc_td_arr_int_d2_4[2,3] = { loc_td_arr_int_d1_1, loc_td_arr_int_d1_2 }; 72 | 73 | real loc_td_arr_real_d1_1[3] = {1.1, 2.2, 3.3}; 74 | real loc_td_arr_real_d1_2[3] = {d_r1, 2, 3}; 75 | real loc_td_arr_real_d1_3[2] = f1_arr_real(); 76 | real loc_td_arr_real_d1_4[1] = f2_arr_real(d_r2); 77 | real loc_td_arr_real_d2_1[1,2] = {{4.4, 5.5}}; 78 | real loc_td_arr_real_d2_2[1,2] = {{4.4, d_r2}}; 79 | 80 | print("loc_td_arr_int_d1_1 = ", loc_td_arr_int_d1_1); 81 | print("loc_td_arr_int_d1_2 = ", loc_td_arr_int_d1_2); 82 | print("loc_td_arr_int_d1_3 = ",loc_td_arr_int_d1_3); 83 | print("loc_td_arr_int_d1_4 = ",loc_td_arr_int_d1_4); 84 | print("loc_td_arr_int_d2_1 = ",loc_td_arr_int_d2_1); 85 | print("loc_td_arr_int_d2_2 = ",loc_td_arr_int_d2_2); 86 | print("loc_td_arr_int_d2_3 = ",loc_td_arr_int_d2_3); 87 | print("loc_td_arr_int_d2_4 = ",loc_td_arr_int_d2_4); 88 | print(""); 89 | print("loc_td_arr_real_d1_1 = ",loc_td_arr_real_d1_1); 90 | print("loc_td_arr_real_d1_2 = ",loc_td_arr_real_d1_2); 91 | print("loc_td_arr_real_d1_3 = ",loc_td_arr_real_d1_3); 92 | print("loc_td_arr_real_d1_4 = ",loc_td_arr_real_d1_4); 93 | print("loc_td_arr_real_d2_1 = ",loc_td_arr_real_d2_1); 94 | print("loc_td_arr_real_d2_2 = ",loc_td_arr_real_d2_2); 95 | print(""); 96 | } 97 | } 98 | parameters { 99 | 100 | } 101 | transformed parameters { 102 | real tp1 = 0.1; 103 | real tp2 = 0.2; 104 | 105 | real tp_arr_real_d1_1[3] = {1.1, 2.2, 3.3}; 106 | real tp_arr_real_d1_2[3] = {d_r1, 2, 3}; 107 | real tp_arr_real_d1_3[2] = f1_arr_real(); 108 | real tp_arr_real_d1_4[1] = f2_arr_real(d_r2); 109 | real tp_arr_real_d1_5[2] = { tp1, tp2 }; 110 | 111 | real tp_arr_real_d2_1[1,2] = {{4.4, 5.5}}; 112 | real tp_arr_real_d2_2[1,2] = {{4.4, d_r2}}; 113 | real tp_arr_real_d2_3[1,2] = {{ tp1, tp2 }}; 114 | 115 | print("tp_arr_real_d1_1 = ",tp_arr_real_d1_1); 116 | print("tp_arr_real_d1_2 = ",tp_arr_real_d1_2); 117 | print("tp_arr_real_d1_3 = ",tp_arr_real_d1_3); 118 | print("tp_arr_real_d1_4 = ",tp_arr_real_d1_4); 119 | print("tp_arr_real_d1_5 = ",tp_arr_real_d1_5); 120 | print("tp_arr_real_d2_1 = ",tp_arr_real_d2_1); 121 | print("tp_arr_real_d2_2 = ",tp_arr_real_d2_2); 122 | print("tp_arr_real_d2_3 = ",tp_arr_real_d2_3); 123 | print(""); 124 | } 125 | model { 126 | } 127 | generated quantities { 128 | int gq_arr_int_d1_1[3] = {1, 2, 3}; 129 | int gq_arr_int_d1_2[3] = {d_i1, 2, 3}; 130 | int gq_arr_int_d1_3[2] = f1_arr_int(); 131 | int gq_arr_int_d1_4[1] = f2_arr_int(d_i2); 132 | int gq_arr_int_d2_1[1,2] = {{4, 5}}; 133 | int gq_arr_int_d2_2[1,2] = {{4, d_i3}}; 134 | int gq_arr_int_d2_3[2,3] = {{1,2,3},{4,5,6}}; 135 | int gq_arr_int_d2_4[2,3] = { gq_arr_int_d1_1, gq_arr_int_d1_2 }; 136 | 137 | real gq_arr_real_d1_1[3] = {1.1, 2.2, 3.3}; 138 | real gq_arr_real_d1_2[3] = {d_r1, 2, 3}; 139 | real gq_arr_real_d1_3[2] = f1_arr_real(); 140 | real gq_arr_real_d1_4[1] = f2_arr_real(d_r2); 141 | real gq_arr_real_d2_1[1,2] = {{4.4, 5.5}}; 142 | real gq_arr_real_d2_2[1,2] = {{4.4, d_r2}}; 143 | 144 | print("gq_arr_int_d1_1 = ", gq_arr_int_d1_1); 145 | print("gq_arr_int_d1_2 = ", gq_arr_int_d1_2); 146 | print("gq_arr_int_d1_3 = ",gq_arr_int_d1_3); 147 | print("gq_arr_int_d1_4 = ",gq_arr_int_d1_4); 148 | print("gq_arr_int_d2_1 = ",gq_arr_int_d2_1); 149 | print("gq_arr_int_d2_2 = ",gq_arr_int_d2_2); 150 | print("gq_arr_int_d2_3 = ",gq_arr_int_d2_3); 151 | print("gq_arr_int_d2_4 = ",gq_arr_int_d2_4); 152 | print(""); 153 | print("gq_arr_real_d1_1 = ",gq_arr_real_d1_1); 154 | print("gq_arr_real_d1_2 = ",gq_arr_real_d1_2); 155 | print("gq_arr_real_d1_3 = ",gq_arr_real_d1_3); 156 | print("gq_arr_real_d1_4 = ",gq_arr_real_d1_4); 157 | print("gq_arr_real_d2_1 = ",gq_arr_real_d2_1); 158 | print("gq_arr_real_d2_2 = ",gq_arr_real_d2_2); 159 | print(""); 160 | 161 | { 162 | int loc_gq_arr_int_d1_1[3] = {1, 2, 3}; 163 | int loc_gq_arr_int_d1_2[3] = {d_i1, 2, 3}; 164 | int loc_gq_arr_int_d1_3[2] = f1_arr_int(); 165 | int loc_gq_arr_int_d1_4[1] = f2_arr_int(d_i2); 166 | int loc_gq_arr_int_d2_1[1,2] = {{4, 5}}; 167 | int loc_gq_arr_int_d2_2[1,2] = {{4, d_i3}}; 168 | int loc_gq_arr_int_d2_3[2,3] = {{1,2,3},{4,5,6}}; 169 | int loc_gq_arr_int_d2_4[2,3] = { loc_gq_arr_int_d1_1, loc_gq_arr_int_d1_2 }; 170 | 171 | real loc_gq_arr_real_d1_1[3] = {1.1, 2.2, 3.3}; 172 | real loc_gq_arr_real_d1_2[3] = {d_r1, 2, 3}; 173 | real loc_gq_arr_real_d1_3[2] = f1_arr_real(); 174 | real loc_gq_arr_real_d1_4[1] = f2_arr_real(d_r2); 175 | real loc_gq_arr_real_d2_1[1,2] = {{4.4, 5.5}}; 176 | real loc_gq_arr_real_d2_2[1,2] = {{4.4, d_r2}}; 177 | 178 | print("loc_gq_arr_int_d1_1 = ", loc_gq_arr_int_d1_1); 179 | print("loc_gq_arr_int_d1_2 = ", loc_gq_arr_int_d1_2); 180 | print("loc_gq_arr_int_d1_3 = ",loc_gq_arr_int_d1_3); 181 | print("loc_gq_arr_int_d1_4 = ",loc_gq_arr_int_d1_4); 182 | print("loc_gq_arr_int_d2_1 = ",loc_gq_arr_int_d2_1); 183 | print("loc_gq_arr_int_d2_2 = ",loc_gq_arr_int_d2_2); 184 | print(""); 185 | print("loc_gq_arr_real_d1_1 = ",loc_gq_arr_real_d1_1); 186 | print("loc_gq_arr_real_d1_2 = ",loc_gq_arr_real_d1_2); 187 | print("loc_gq_arr_real_d1_3 = ",loc_gq_arr_real_d1_3); 188 | print("loc_gq_arr_real_d1_4 = ",loc_gq_arr_real_d1_4); 189 | print("loc_gq_arr_real_d2_1 = ",loc_gq_arr_real_d2_1); 190 | print("loc_gq_arr_real_d2_2 = ",loc_gq_arr_real_d2_2); 191 | print(""); 192 | } 193 | } 194 | """ 195 | 196 | data = { 197 | 'd_i1': 2, 198 | 'd_i2': 3, 199 | 'd_i3': 5, 200 | 'd_r1': 8.0, 201 | 'd_r2': 13.0, 202 | 'd_r3': 21.0 203 | } 204 | 205 | compare_models(stan_code, data, algorithm='fixed_param') 206 | 207 | 208 | if __name__ == "__main__": 209 | test_validate_arr_expr_primitives() 210 | -------------------------------------------------------------------------------- /tests/runtime/test_vectorized_probability.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .utils import compare_models 3 | 4 | 5 | def test_vectorized_probability(): 6 | stan_code = """ 7 | data { 8 | int K; 9 | int N; 10 | matrix[N, K] x; 11 | vector[N] y; 12 | } 13 | parameters { 14 | vector[K] beta; 15 | } 16 | model { 17 | y ~ normal(x * beta, 1); 18 | } 19 | """ 20 | 21 | num_samples = 100 22 | num_features = 2 23 | #X = np.array([[1, 1], [1, 2], [2, 2], [2, 3]]) 24 | X = np.random.randint(5, size=(100, 2)) 25 | # y = 1 * x_0 + 2 * x_1 + 3 26 | y = np.dot(X, np.array([1, 2])) + 3 27 | 28 | data = {'N': num_samples, 29 | 'K': num_features, 30 | 'x': X, 31 | 'y': y} 32 | 33 | compare_models(stan_code, data) 34 | 35 | 36 | if __name__ == "__main__": 37 | test_vectorized_probability() 38 | -------------------------------------------------------------------------------- /tests/runtime/utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from pycmdstan.model import Model 3 | import pycmdstan 4 | import yaps 5 | 6 | global_num_iterations = 10 7 | global_random_seed = 42 8 | 9 | 10 | def compare_fit_objects(fit_stan, fit_generated_stan): 11 | # Check that the number of parameters are equal 12 | assert len(fit_stan.csv) == len(fit_generated_stan.csv) 13 | for param_name in fit_stan.csv: 14 | param_stan = fit_stan.csv[param_name] 15 | param_generated_stan = fit_generated_stan.csv[param_name] 16 | if(isinstance(param_stan, np.ndarray)): 17 | assert np.all(param_stan == param_generated_stan) 18 | else: 19 | assert param_stan == param_generated_stan 20 | 21 | 22 | def compare_models(stan_code, data, **kwargs): 23 | # Round Trip from Stan to Yaps to Stan 24 | yaps_code = yaps.from_stan(code_string=stan_code) 25 | generated_stan_code = yaps.to_stan(yaps_code) 26 | # Compile and fit original code 27 | sm1 = Model(code=str(stan_code)) 28 | fit_stan = sm1.sample(**kwargs, 29 | data=data, 30 | num_samples=global_num_iterations, 31 | random_='seed={}'.format(global_random_seed)) 32 | # Compile and fit generated code 33 | sm2 = Model(code=str(generated_stan_code)) 34 | fit_generated_stan = sm2.sample(**kwargs, 35 | data=data, 36 | num_samples=global_num_iterations, 37 | random_='seed={}'.format(global_random_seed)) 38 | # Compare results 39 | compare_fit_objects(fit_stan, fit_generated_stan) 40 | -------------------------------------------------------------------------------- /tests/stan/ch02_02_comment.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; // number of observations 3 | real y[N]; // observations 4 | } 5 | -------------------------------------------------------------------------------- /tests/stan/ch02_02_include.stan: -------------------------------------------------------------------------------- 1 | #include ch02_2_std_normal.stan 2 | parameters { 3 | real y; 4 | } 5 | model { 6 | y ~ std_normal(); 7 | } 8 | -------------------------------------------------------------------------------- /tests/stan/ch02_02_inline.stan: -------------------------------------------------------------------------------- 1 | functions { 2 | real std_normal_lpdf(vector y) { 3 | return -0.5 * y' * y; 4 | } 5 | } 6 | parameters { 7 | real y; 8 | } 9 | model { 10 | y ~ std_normal(); 11 | } 12 | -------------------------------------------------------------------------------- /tests/stan/ch02_02_std_normal.stan: -------------------------------------------------------------------------------- 1 | functions { 2 | real std_normal_lpdf(vector y) { 3 | return -0.5 * y' * y; 4 | } 5 | } -------------------------------------------------------------------------------- /tests/stan/ch03_03_bound_1.stan: -------------------------------------------------------------------------------- 1 | data { 2 | real lb; 3 | } 4 | parameters { 5 | real phi; 6 | } -------------------------------------------------------------------------------- /tests/stan/ch03_03_bound_2.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | real y[N]; 4 | } 5 | parameters { 6 | real phi; 7 | } -------------------------------------------------------------------------------- /tests/stan/ch04_11_chain_rule.stan: -------------------------------------------------------------------------------- 1 | parameters { 2 | real x; 3 | } 4 | model { 5 | x ~ normal(sqrt(x - x), 1); 6 | } 7 | -------------------------------------------------------------------------------- /tests/stan/ch05_9_print.stan: -------------------------------------------------------------------------------- 1 | transformed data { 2 | matrix[2, 2] u; 3 | u[1, 1] = 1.0; u[1, 2] = 4.0; 4 | u[2, 1] = 9.0; u[2, 2] = 16.0; 5 | for (n in 1:2) 6 | print("u[", n, "] = ", u[n]); 7 | } -------------------------------------------------------------------------------- /tests/stan/ch06_2_variables.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; // unmodeled data 3 | real y[N]; // modeled data 4 | real mu_mu; // config. unmodeled param 5 | real sigma_mu; // config. unmodeled param 6 | } 7 | transformed data { 8 | real alpha; // const. unmodeled param 9 | real beta; // const. unmodeled param 10 | alpha = 0.1; 11 | beta = 0.1; 12 | } 13 | parameters { 14 | real mu_y; // modeled param 15 | real tau_y; // modeled param 16 | } 17 | transformed parameters { 18 | real sigma_y; // derived quantity (param) 19 | sigma_y = pow(tau_y, -0.5); 20 | } 21 | model { 22 | tau_y ~ gamma(alpha, beta); 23 | mu_y ~ normal(mu_mu, sigma_mu); 24 | for (n in 1:N) 25 | y[n] ~ normal(mu_y, sigma_y); 26 | } 27 | generated quantities { 28 | real variance_y; // derived quantity (transform) 29 | variance_y = sigma_y * sigma_y; 30 | } -------------------------------------------------------------------------------- /tests/stan/ch09_regression.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | vector[N] x; 4 | vector[N] y; 5 | } 6 | parameters { 7 | real alpha; 8 | real beta; 9 | real sigma; 10 | } 11 | model { 12 | y ~ normal(alpha + beta * x, sigma); 13 | } -------------------------------------------------------------------------------- /tests/stan/ch09_regression_bernoulli.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | vector[N] x; 4 | int y[N]; 5 | } 6 | parameters { 7 | real alpha; 8 | real beta; 9 | } 10 | model { 11 | y ~ bernoulli_logit(alpha + beta * x); 12 | } -------------------------------------------------------------------------------- /tests/stan/ch09_regression_matrix.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | int K; 4 | matrix[N, K] x; 5 | vector[N] y; 6 | } 7 | parameters { 8 | real alpha; 9 | vector[K] beta; 10 | real sigma; 11 | } 12 | model { 13 | y ~ normal(x * beta + alpha, sigma); 14 | } -------------------------------------------------------------------------------- /tests/stan/ch09_regression_qr.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | int K; 4 | matrix[N, K] x; 5 | vector[N] y; 6 | } 7 | transformed data { 8 | matrix[N, K] Q_ast; 9 | matrix[K, K] R_ast; 10 | matrix[K, K] R_ast_inverse; 11 | Q_ast = qr_Q(x)[, 1:K] * sqrt(N - 1); 12 | R_ast = qr_R(x)[1:K, ] / sqrt(N - 1); 13 | R_ast_inverse = inverse(R_ast); 14 | } 15 | parameters { 16 | real alpha; 17 | vector[K] theta; 18 | real sigma; 19 | } 20 | model { 21 | y ~ normal(Q_ast * theta + alpha, sigma); 22 | } 23 | generated quantities { 24 | vector[K] beta; 25 | beta = R_ast_inverse * theta; 26 | } -------------------------------------------------------------------------------- /tests/stan/ch10_time_ar_1.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | vector[N] y; 4 | } 5 | parameters { 6 | real alpha; 7 | real beta; 8 | real sigma; 9 | } 10 | model { 11 | for (n in 2:N) 12 | y[n] ~ normal(alpha + beta * y[n-1], sigma); 13 | } -------------------------------------------------------------------------------- /tests/stan/ch10_time_ar_k.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int K; 3 | int N; 4 | real y[N]; 5 | } 6 | parameters { 7 | real alpha; 8 | real beta[K]; 9 | real sigma; 10 | } 11 | model { 12 | for (n in (K+1):N) { 13 | real mu = alpha; 14 | for (k in 1:K) 15 | mu += beta[k] * y[n-k]; 16 | y[n] ~ normal(mu, sigma); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/stan/ch10_time_arch_1.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int T; 3 | real r[T]; 4 | } 5 | parameters { 6 | real mu; 7 | real alpha0; // noise intercept 8 | real alpha1; // noise slope 9 | } 10 | model { 11 | for (t in 2:T) 12 | r[t] ~ normal(mu, sqrt(alpha0 + alpha1 * pow(r[t-1] - mu,2))); 13 | } 14 | -------------------------------------------------------------------------------- /tests/stan/ch10_time_arma_1_1.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int T; // num observations 3 | real y[T]; // observed outputs 4 | } 5 | parameters { 6 | real mu; // mean coeff 7 | real phi; // autoregression coeff 8 | real theta; // moving avg coeff 9 | real sigma; // noise scale 10 | } 11 | model { 12 | vector[T] nu; // prediction for time t 13 | vector[T] err; // error for time t 14 | nu[1] = mu + phi * mu; // assume err[0] == 0 15 | err[1] = y[1] - nu[1]; 16 | for (t in 2:T) { 17 | nu[t] = mu + phi * y[t-1] + theta * err[t-1]; 18 | err[t] = y[t] - nu[t]; 19 | } 20 | mu ~ normal(0, 10); // priors 21 | phi ~ normal(0, 2); 22 | theta ~ normal(0, 2); 23 | sigma ~ cauchy(0, 5); 24 | err ~ normal(0, sigma); // likelihood 25 | } -------------------------------------------------------------------------------- /tests/stan/ch10_time_garch_1_1.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int T; 3 | real r[T]; 4 | real sigma1; 5 | } 6 | parameters { 7 | real mu; 8 | real alpha0; 9 | real alpha1; 10 | real beta1; 11 | } 12 | transformed parameters { 13 | real sigma[T]; 14 | sigma[1] = sigma1; 15 | for (t in 2:T) 16 | sigma[t] = sqrt(alpha0 17 | + alpha1 * pow(r[t-1] - mu, 2) 18 | + beta1 * pow(sigma[t-1], 2)); 19 | } 20 | model { 21 | r ~ normal(mu, sigma); 22 | } -------------------------------------------------------------------------------- /tests/stan/ch10_time_hmm_supervised.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int K; // num categories 3 | int V; // num words 4 | int T; // num instances 5 | int w[T]; // words 6 | int z[T]; // categories 7 | vector[K] alpha; // transit prior 8 | vector[V] beta; // emit prior 9 | } 10 | parameters { 11 | simplex[K] theta[K]; // transit probs 12 | simplex[V] phi[K]; // emit probs 13 | } 14 | model { 15 | for (k in 1:K) 16 | theta[k] ~ dirichlet(alpha); 17 | for (k in 1:K) 18 | phi[k] ~ dirichlet(beta); 19 | for (t in 1:T) 20 | w[t] ~ categorical(phi[z[t]]); 21 | for (t in 2:T) 22 | z[t] ~ categorical(theta[z[t - 1]]); 23 | } 24 | -------------------------------------------------------------------------------- /tests/stan/ch10_time_ma_2.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int T; // number of observations 3 | vector[T] y; // observation at time T 4 | } 5 | parameters { 6 | real mu; // mean 7 | real sigma; // error scale 8 | vector[2] theta; // lag coefficients 9 | } 10 | transformed parameters { 11 | vector[T] epsilon; // error terms 12 | epsilon[1] = y[1] - mu; 13 | epsilon[2] = y[2] - mu - theta[1] * epsilon[1]; 14 | for (t in 3:T) 15 | epsilon[t] = ( y[t] - mu 16 | - theta[1] * epsilon[t - 1] 17 | - theta[2] * epsilon[t - 2] ); 18 | } 19 | model { 20 | mu ~ cauchy(0, 2.5); 21 | theta ~ cauchy(0, 2.5); 22 | sigma ~ cauchy(0, 2.5); 23 | for (t in 3:T) 24 | y[t] ~ normal(mu 25 | + theta[1] * epsilon[t - 1] 26 | + theta[2] * epsilon[t - 2], 27 | sigma); 28 | } 29 | -------------------------------------------------------------------------------- /tests/stan/ch10_time_ma_q.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int Q; // num previous noise terms 3 | int T; // num observations 4 | vector[T] y; // observation at time t 5 | } 6 | parameters { 7 | real mu; // mean 8 | real sigma; // error scale 9 | vector[Q] theta; // error coeff, lag -t 10 | } 11 | transformed parameters { 12 | vector[T] epsilon; // error term at time t 13 | for (t in 1:T) { 14 | epsilon[t] = y[t] - mu; 15 | for (q in 1:min(t - 1, Q)) 16 | epsilon[t] = epsilon[t] - theta[q] * epsilon[t - q]; 17 | } 18 | } 19 | model { 20 | vector[T] eta; 21 | mu ~ cauchy(0, 2.5); 22 | theta ~ cauchy(0, 2.5); 23 | sigma ~ cauchy(0, 2.5); 24 | for (t in 1:T) { 25 | eta[t] = mu; 26 | for (q in 1:min(t - 1, Q)) 27 | eta[t] = eta[t] + theta[q] * epsilon[t - q]; 28 | } 29 | y ~ normal(eta, sigma); 30 | } -------------------------------------------------------------------------------- /tests/stan/ch10_time_svm.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int T; // # time points (equally spaced) 3 | vector[T] y; // mean corrected return at time t 4 | } 5 | parameters { 6 | real mu; // mean log volatility 7 | real phi; // persistence of volatility 8 | real sigma; // white noise shock scale 9 | vector[T] h; // log volatility at time t 10 | } 11 | model { 12 | phi ~ uniform(-1, 1); 13 | sigma ~ cauchy(0, 5); 14 | mu ~ cauchy(0, 10); 15 | h[1] ~ normal(mu, sigma / sqrt(1 - phi * phi)); 16 | for (t in 2:T) 17 | h[t] ~ normal(mu + phi * (h[t - 1] - mu), sigma); 18 | for (t in 1:T) 19 | y[t] ~ normal(0, exp(h[t] / 2)); 20 | } 21 | -------------------------------------------------------------------------------- /tests/stan/ch11_loading_matrix.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int K; 3 | } 4 | transformed data { 5 | int K_choose_2; 6 | K_choose_2 = (K * (K - 1)) / 2; 7 | } 8 | parameters { 9 | vector[K_choose_2] L_lower; 10 | } 11 | transformed parameters { 12 | cholesky_factor_cov[K] L; 13 | for (k in 1:K) 14 | L[k, k] = 1; 15 | { 16 | int i; 17 | for (m in 2:K) { 18 | for (n in 1:(m - 1)) { 19 | L[m, n] = L_lower[i]; 20 | L[n, m] = 0; 21 | i += 1; 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /tests/stan/ch11_missing_data.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N_obs; 3 | int N_mis; 4 | real y_obs[N_obs]; 5 | } 6 | parameters { 7 | real mu; 8 | real sigma; 9 | real y_mis[N_mis]; 10 | } 11 | model { 12 | y_obs ~ normal(mu, sigma); 13 | y_mis ~ normal(mu, sigma); 14 | } -------------------------------------------------------------------------------- /tests/stan/ch11_partially_known_paramters.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | vector[2] y[N]; 4 | real var1; real var2; 5 | } 6 | transformed data { 7 | real max_cov = sqrt(var1 * var2); 8 | real min_cov = -max_cov; 9 | } 10 | parameters { 11 | vector[2] mu; 12 | real cov; 13 | } 14 | transformed parameters { 15 | matrix[2, 2] Sigma; 16 | Sigma[1, 1] = var1; Sigma[1, 2] = cov; 17 | Sigma[2, 1] = cov; Sigma[2, 2] = var2; 18 | } 19 | model { 20 | y ~ multi_normal(mu, Sigma); 21 | } 22 | -------------------------------------------------------------------------------- /tests/stan/ch11_sliced_missing_data.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N_obs; 3 | int N_mis; 4 | int ii_obs[N_obs]; 5 | int ii_mis[N_mis]; 6 | real y_obs[N_obs]; 7 | } 8 | transformed data { 9 | int N = N_obs + N_mis; 10 | } 11 | parameters { 12 | real y_mis[N_mis]; 13 | real sigma; 14 | } 15 | transformed parameters { 16 | real y[N]; 17 | y[ii_obs] = y_obs; 18 | y[ii_mis] = y_mis; 19 | } 20 | model { 21 | sigma ~ gamma(1, 1); 22 | y[1] ~ normal(0, 100); 23 | y[2:N] ~ normal(y[1:(N - 1)], sigma); 24 | } 25 | -------------------------------------------------------------------------------- /tests/stan/ch12_estimate_censored.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N_obs; 3 | int N_cens; 4 | real y_obs[N_obs]; 5 | real U; 6 | } 7 | parameters { 8 | real y_cens[N_cens]; 9 | real mu; 10 | real sigma; 11 | } 12 | model { 13 | y_obs ~ normal(mu, sigma); 14 | y_cens ~ normal(mu, sigma); 15 | } -------------------------------------------------------------------------------- /tests/stan/ch12_integrate_censored.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N_obs; 3 | int N_cens; 4 | real y_obs[N_obs]; 5 | real U; 6 | } 7 | parameters { 8 | real mu; 9 | real sigma; 10 | } 11 | model { 12 | y_obs ~ normal(mu, sigma); 13 | target += N_cens * normal_lccdf(U | mu, sigma); 14 | } 15 | -------------------------------------------------------------------------------- /tests/stan/ch12_integrate_censored_2.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N_obs; 3 | int N_cens; 4 | real y_obs[N_obs]; 5 | } 6 | parameters { 7 | real L; 8 | real mu; 9 | real sigma; 10 | } 11 | model { 12 | L ~ normal(mu, sigma); 13 | y_obs ~ normal(mu, sigma); 14 | target += N_cens * normal_lcdf(L | mu, sigma); 15 | } -------------------------------------------------------------------------------- /tests/stan/ch12_truncated.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | real U; 4 | real y[N]; 5 | } 6 | parameters { 7 | real mu; 8 | real sigma; 9 | } 10 | model { 11 | for (n in 1:N) 12 | y[n] ~ normal(mu, sigma) T[,U]; 13 | } 14 | -------------------------------------------------------------------------------- /tests/stan/ch13_log_sum_of_exp.stan: -------------------------------------------------------------------------------- 1 | parameters { 2 | real y; 3 | } 4 | model { 5 | target += log_sum_exp(log(0.3) + normal_lpdf(y | -1, 2), 6 | log(0.7) + normal_lpdf(y | 3, 1)); 7 | } -------------------------------------------------------------------------------- /tests/stan/ch13_zero_inflation.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | int y[N]; 4 | } 5 | parameters { 6 | real theta; 7 | real lambda_; 8 | } 9 | model { 10 | for (n in 1:N) { 11 | if (y[n] == 0) 12 | target += log_sum_exp(bernoulli_lpmf(1 | theta), 13 | bernoulli_lpmf(0 | theta) 14 | + poisson_lpmf(y[n] | lambda_)); 15 | else 16 | target += bernoulli_lpmf(0 | theta) 17 | + poisson_lpmf(y[n] | lambda_); 18 | } 19 | } -------------------------------------------------------------------------------- /tests/stan/ch14_regression_error.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | real x[N]; 4 | real y[N]; 5 | } 6 | parameters { 7 | real alpha; 8 | real beta; 9 | real sigma; // outcome noise 10 | } 11 | model { 12 | y ~ normal(alpha + beta * x, sigma); 13 | alpha ~ normal(0, 10); 14 | beta ~ normal(0, 10); 15 | sigma ~ cauchy(0, 5); 16 | } -------------------------------------------------------------------------------- /tests/stan/ch14_rounding.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | vector[N] y; 4 | } 5 | parameters { 6 | real mu; 7 | real sigma_sq; 8 | } 9 | transformed parameters { 10 | real sigma; 11 | sigma = sqrt(sigma_sq); 12 | } 13 | model { 14 | target += -2 * log(sigma); 15 | for (n in 1:N) 16 | target += log(Phi((y[n] + 0.5 - mu) / sigma) 17 | - Phi((y[n] - 0.5 - mu) / sigma)); 18 | } 19 | -------------------------------------------------------------------------------- /tests/stan/ch14_rounding_2.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | vector[N] y; 4 | } 5 | parameters { 6 | real mu; 7 | real sigma_sq; 8 | vector[N] y_err; 9 | } 10 | transformed parameters { 11 | real sigma; 12 | vector[N] z; 13 | sigma = sqrt(sigma_sq); 14 | z = y + y_err; 15 | } 16 | model { 17 | target += -2 * log(sigma); 18 | z ~ normal(mu, sigma); 19 | } -------------------------------------------------------------------------------- /tests/stan/ch15_change_point.stan: -------------------------------------------------------------------------------- 1 | data { 2 | real r_e; 3 | real r_l; 4 | int T; 5 | int D[T]; 6 | } 7 | transformed data { 8 | real log_unif; 9 | log_unif = -log(T); 10 | } 11 | parameters { 12 | real e; 13 | real l; 14 | } 15 | transformed parameters { 16 | vector[T] lp; 17 | lp = rep_vector(log_unif, T); 18 | for (s in 1:T) 19 | for (t in 1:T) 20 | lp[s] = lp[s] + poisson_lpmf(D[t] | t < s ? e : l); 21 | } 22 | model { 23 | e ~ exponential(r_e); 24 | l ~ exponential(r_l); 25 | target += log_sum_exp(lp); 26 | } 27 | -------------------------------------------------------------------------------- /tests/stan/ch15_cormack_jolly_seber.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int history[7]; 3 | } 4 | parameters { 5 | real phi[2]; 6 | real p[3]; 7 | } 8 | transformed parameters { 9 | real chi[2]; 10 | chi[2] = (1 - phi[2]) + phi[2] * (1 - p[3]); 11 | chi[1] = (1 - phi[1]) + phi[1] * (1 - p[2]) * chi[2]; 12 | } 13 | model { 14 | target += history[2] * log(chi[2]); 15 | target += history[3] * (log(phi[2]) + log(p[3])); 16 | target += history[4] * (log(chi[1])); 17 | target += history[5] * (log(phi[1]) + log1m(p[2]) 18 | + log(phi[2]) + log(p[3])); 19 | target += history[6] * (log(phi[1]) + log(p[2]) 20 | + log(chi[2])); 21 | target += history[7] * (log(phi[1]) + log(p[2]) 22 | + log(phi[2]) + log(p[3])); 23 | } 24 | generated quantities { 25 | real beta3; 26 | beta3 = phi[2] * p[3]; 27 | } -------------------------------------------------------------------------------- /tests/stan/ch15_dawid_skene.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int K; 3 | int I; 4 | int J; 5 | int y[I, J]; 6 | vector[K] alpha; 7 | vector[K] beta[K]; 8 | } 9 | parameters { 10 | simplex[K] pi; 11 | simplex[K] theta[J, K]; 12 | } 13 | transformed parameters { 14 | vector[K] log_q_z[I]; 15 | for (i in 1:I) { 16 | log_q_z[i] = log(pi); 17 | for (j in 1:J) 18 | for (k in 1:K) 19 | log_q_z[i, k] = log_q_z[i, k] 20 | + log(theta[j, k, y[i, j]]); 21 | } } 22 | model { 23 | pi ~ dirichlet(alpha); 24 | for (j in 1:J) 25 | for (k in 1:K) 26 | theta[j, k] ~ dirichlet(beta[k]); 27 | for (i in 1:I) 28 | target += log_sum_exp(log_q_z[i]); 29 | } -------------------------------------------------------------------------------- /tests/stan/ch15_lincoln_petersen.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int M; 3 | int C; 4 | int R; 5 | } 6 | parameters { 7 | real N; 8 | } 9 | model { 10 | R ~ binomial(C, M / N); 11 | } -------------------------------------------------------------------------------- /tests/stan/ch17_k_means.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; // number of data points 3 | int D; // number of dimensions 4 | int K; // number of clusters 5 | vector[D] y[N]; // observations 6 | } 7 | transformed data { 8 | real neg_log_K; 9 | neg_log_K = -log(K); 10 | } 11 | parameters { 12 | vector[D] mu[K]; // cluster means 13 | } 14 | transformed parameters { 15 | real soft_z[N, K]; // log unnormalized clusters 16 | for (n in 1:N) 17 | for (k in 1:K) 18 | soft_z[n, k] = neg_log_K 19 | - 0.5 * dot_self(mu[k] - y[n]); 20 | } 21 | model { 22 | // prior 23 | for (k in 1:K) 24 | mu[k] ~ normal(0, 1); 25 | // likelihood 26 | for (n in 1:N) 27 | target += log_sum_exp(soft_z[n]); 28 | } -------------------------------------------------------------------------------- /tests/stan/ch17_lda.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int K; 3 | int V; 4 | int M; 5 | int N; 6 | int w[N]; 7 | int doc[N]; // doc ID for word n 8 | vector[K] alpha; // topic prior 9 | vector[V] beta; // word prior 10 | } 11 | parameters { 12 | simplex[K] theta[M]; 13 | simplex[V] phi[K]; 14 | } model { 15 | // topic dist for doc m 16 | // word dist for topic k 17 | for (m in 1:M) 18 | theta[m] ~ dirichlet(alpha); // prior 19 | for (k in 1:K) 20 | phi[k] ~ dirichlet(beta); // prior 21 | for (n in 1:N) { 22 | real gamma[K]; 23 | for (k in 1:K) 24 | gamma[k] = log(theta[doc[n], k]) + log(phi[k, w[n]]); 25 | target += log_sum_exp(gamma); // likelihood; 26 | } 27 | } -------------------------------------------------------------------------------- /tests/stan/ch17_naive_bayes.stan: -------------------------------------------------------------------------------- 1 | data { 2 | // training data 3 | int K; 4 | int V; 5 | int M; 6 | int N; 7 | int z[M]; 8 | int w[N]; 9 | int doc[N]; // doc ID for word n 10 | // hyperparameters 11 | vector[K] alpha; // topic prior 12 | vector[V] beta; // word prior 13 | } 14 | parameters { 15 | simplex[K] theta; // topic prevalence 16 | simplex[V] phi[K]; // word dist for topic k 17 | } 18 | model { 19 | theta ~ dirichlet(alpha); 20 | for (k in 1:K) 21 | phi[k] ~ dirichlet(beta); 22 | for (m in 1:M) 23 | z[m] ~ categorical(theta); 24 | for (n in 1:N) 25 | w[n] ~ categorical(phi[z[doc[n]]]); 26 | } -------------------------------------------------------------------------------- /tests/stan/ch18_fitting_gaussian_process.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | real x[N]; 4 | vector[N] y; 5 | } 6 | transformed data { 7 | vector[N] mu = rep_vector(0, N); 8 | } 9 | parameters { 10 | real rho; 11 | real alpha; 12 | real sigma; 13 | } 14 | model { 15 | matrix[N, N] L_K; 16 | matrix[N, N] K = cov_exp_quad(x, alpha, rho); 17 | real sq_sigma = square(sigma); 18 | // diagonal elements 19 | for (n in 1:N) 20 | K[n, n] = K[n, n] + sq_sigma; 21 | L_K = cholesky_decompose(K); 22 | rho ~ inv_gamma(5, 5); 23 | alpha ~ normal(0, 1); 24 | sigma ~ normal(0, 1); 25 | y ~ multi_normal_cholesky(mu, L_K); 26 | } 27 | -------------------------------------------------------------------------------- /tests/stan/ch18_gaussian_process.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | real x[N]; 4 | } 5 | transformed data { 6 | matrix[N, N] K; 7 | vector[N] mu = rep_vector(0, N); 8 | for (i in 1:(N - 1)) { 9 | K[i, i] = 1 + 0.1; 10 | for (j in (i + 1):N) { 11 | K[i, j] = exp(-0.5 * square(x[i] - x[j])); 12 | K[j, i] = K[i, j]; 13 | } 14 | } 15 | K[N, N] = 1 + 0.1; 16 | } 17 | parameters { 18 | vector[N] y; 19 | } 20 | model { 21 | y ~ multi_normal(mu, K); 22 | } -------------------------------------------------------------------------------- /tests/stan/ch18_gaussian_process_2.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | real x[N]; 4 | } 5 | transformed data { 6 | matrix[N, N] K = cov_exp_quad(x, 1.0, 1.0); 7 | vector[N] mu = rep_vector(0, N); 8 | for (n in 1:N) 9 | K[n, n] = K[n, n] + 0.1; 10 | } 11 | parameters { 12 | vector[N] y; 13 | } 14 | model { 15 | y ~ multi_normal(mu, K); 16 | } 17 | -------------------------------------------------------------------------------- /tests/stan/ch18_latent_gaussian_process.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | real x[N]; 4 | vector[N] y; 5 | } 6 | transformed data { 7 | real delta = 1e-9; 8 | } 9 | parameters { 10 | real rho; 11 | real alpha; 12 | real sigma; 13 | vector[N] eta; 14 | } 15 | model { 16 | vector[N] f; 17 | { 18 | matrix[N, N] L_K; 19 | matrix[N, N] K = cov_exp_quad(x, alpha, rho); 20 | // diagonal elements 21 | for (n in 1:N) 22 | K[n, n] = K[n, n] + delta; 23 | L_K = cholesky_decompose(K); 24 | f = L_K * eta; 25 | } 26 | rho ~ inv_gamma(5, 5); 27 | alpha ~ normal(0, 1); 28 | sigma ~ normal(0, 1); 29 | eta ~ normal(0, 1); 30 | y ~ normal(f, sigma); 31 | } -------------------------------------------------------------------------------- /tests/stan/ch18_multiple_outputs.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | int D; 4 | real x[N]; 5 | matrix[N, D] y; 6 | } 7 | transformed data { 8 | real delta = 1e-9; 9 | } 10 | parameters { 11 | real rho; 12 | vector[D] alpha; 13 | real sigma; 14 | cholesky_factor_corr[D] L_Omega; 15 | matrix[N, D] eta; 16 | } 17 | model { 18 | matrix[N, D] f; 19 | { 20 | matrix[N, N] K = cov_exp_quad(x, 1.0, rho); 21 | matrix[N, N] L_K; 22 | // diagonal elements 23 | for (n in 1:N) 24 | K[n, n] = K[n, n] + delta; 25 | L_K = cholesky_decompose(K); 26 | f = L_K * eta 27 | * diag_pre_multiply(alpha, L_Omega)'; 28 | } 29 | rho ~ inv_gamma(5, 5); 30 | alpha ~ normal(0, 1); 31 | sigma ~ normal(0, 1); 32 | L_Omega ~ lkj_corr_cholesky(3); 33 | to_vector(eta) ~ normal(0, 1); 34 | to_vector(y) ~ normal(to_vector(f), sigma); 35 | } 36 | generated quantities { 37 | matrix[D, D] Omega; 38 | Omega = L_Omega * L_Omega'; 39 | } -------------------------------------------------------------------------------- /tests/stan/ch18_predictive_inference.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N1; 3 | real x1[N1]; 4 | vector[N1] y1; 5 | int N2; 6 | real x2[N2]; 7 | } 8 | transformed data { 9 | real delta = 1e-9; 10 | int N = N1 + N2; 11 | real x[N]; 12 | for (n1 in 1:N1) x[n1] = x1[n1]; 13 | for (n2 in 1:N2) x[N1 + n2] = x2[n2]; 14 | } 15 | parameters { 16 | real rho; 17 | real alpha; 18 | real sigma; 19 | vector[N] eta; 20 | } 21 | transformed parameters { 22 | vector[N] f; 23 | { 24 | matrix[N, N] L_K; 25 | matrix[N, N] K = cov_exp_quad(x, alpha, rho); 26 | // diagonal elements 27 | for (n in 1:N) 28 | K[n, n] = K[n, n] + delta; 29 | L_K = cholesky_decompose(K); 30 | f = L_K * eta; 31 | } 32 | } 33 | model { 34 | rho ~ inv_gamma(5, 5); 35 | alpha ~ normal(0, 1); 36 | sigma ~ normal(0, 1); 37 | eta ~ normal(0, 1); 38 | y1 ~ normal(f[1:N1], sigma); 39 | } 40 | generated quantities { 41 | vector[N2] y2; 42 | for (n2 in 1:N2) 43 | y2[n2] = normal_rng(f[N1 + n2], sigma); 44 | } -------------------------------------------------------------------------------- /tests/stan/ch18_predictive_inference_2.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N1; 3 | real x1[N1]; 4 | int z1[N1]; 5 | int N2; 6 | real x2[N2]; 7 | } 8 | transformed data { 9 | real delta = 1e-9; 10 | int N = N1 + N2; 11 | real x[N]; 12 | for (n1 in 1:N1) x[n1] = x1[n1]; 13 | for (n2 in 1:N2) x[N1 + n2] = x2[n2]; 14 | } 15 | parameters { 16 | real rho; 17 | real alpha; 18 | real a; 19 | vector[N] eta; 20 | } 21 | transformed parameters { 22 | vector[N] f; 23 | { 24 | matrix[N, N] L_K; 25 | matrix[N, N] K = cov_exp_quad(x, alpha, rho); 26 | // diagonal elements 27 | for (n in 1:N) 28 | K[n, n] = K[n, n] + delta; 29 | L_K = cholesky_decompose(K); 30 | f = L_K * eta; 31 | } 32 | } 33 | model { 34 | rho ~ inv_gamma(5, 5); 35 | alpha ~ normal(0, 1); 36 | a ~ normal(0, 1); 37 | eta ~ normal(0, 1); 38 | z1 ~ bernoulli_logit(a + f[1:N1]); 39 | } 40 | generated quantities { 41 | int z2[N2]; 42 | for (n2 in 1:N2) 43 | z2[n2] = bernoulli_logit_rng(a + f[N1 + n2]); 44 | } -------------------------------------------------------------------------------- /tests/stan/ch18_predictive_inference_3.stan: -------------------------------------------------------------------------------- 1 | // TODO, declarations in the model are not parameters... 2 | 3 | functions { 4 | vector gp_pred_rng(real[] x2, 5 | vector y1, 6 | real[] x1, 7 | real alpha, 8 | real rho, 9 | real sigma, 10 | real delta) { 11 | int N1 = rows(y1); 12 | int N2 = size(x2); 13 | vector[N2] f2; 14 | { 15 | matrix[N1, N1] L_K; 16 | vector[N1] K_div_y1; 17 | matrix[N1, N2] k_x1_x2; 18 | matrix[N1, N2] v_pred; 19 | vector[N2] f2_mu; 20 | matrix[N2, N2] cov_f2; 21 | matrix[N2, N2] diag_delta; 22 | matrix[N1, N1] K; 23 | K = cov_exp_quad(x1, alpha, rho); 24 | for (n in 1:N1) 25 | K[n, n] = K[n,n] + square(sigma); 26 | L_K = cholesky_decompose(K); 27 | K_div_y1 = mdivide_left_tri_low(L_K, y1); 28 | K_div_y1 = mdivide_right_tri_low(K_div_y1',L_K)'; 29 | k_x1_x2 = cov_exp_quad(x1, x2, alpha, rho); 30 | f2_mu = (k_x1_x2' * K_div_y1); 31 | v_pred = mdivide_left_tri_low(L_K, k_x1_x2); 32 | cov_f2 = cov_exp_quad(x2, alpha, rho) - v_pred' * v_pred; 33 | diag_delta = diag_matrix(rep_vector(delta,N2)); 34 | f2 = multi_normal_rng(f2_mu, cov_f2 + diag_delta); 35 | } 36 | return f2; 37 | } 38 | } 39 | data { 40 | int N1; 41 | real x1[N1]; 42 | vector[N1] y1; 43 | int N2; 44 | real x2[N2]; 45 | } 46 | transformed data { 47 | vector[N1] mu = rep_vector(0, N1); 48 | real delta = 1e-9; 49 | } 50 | parameters { 51 | real rho; 52 | real alpha; 53 | real sigma; 54 | } 55 | model { 56 | matrix[N1, N1] L_K; 57 | { 58 | matrix[N1, N1] K = cov_exp_quad(x1, alpha, rho); 59 | real sq_sigma = square(sigma); 60 | // diagonal elements 61 | for (n1 in 1:N1) 62 | K[n1, n1] = K[n1, n1] + sq_sigma; 63 | L_K = cholesky_decompose(K); 64 | } 65 | rho ~ inv_gamma(5, 5); 66 | alpha ~ normal(0, 1); 67 | sigma ~ normal(0, 1); 68 | y1 ~ multi_normal_cholesky(mu, L_K); 69 | } 70 | generated quantities { 71 | vector[N2] f2; 72 | vector[N2] y2; 73 | f2 = gp_pred_rng(x2, y1, x1, alpha, rho, sigma, delta); 74 | for (n2 in 1:N2) 75 | y2[n2] = normal_rng(f2[n2], sigma); 76 | } 77 | -------------------------------------------------------------------------------- /tests/stan/ch18_relevance_determination.stan: -------------------------------------------------------------------------------- 1 | functions { 2 | matrix L_cov_exp_quad_ARD(vector[] x, 3 | real alpha, 4 | vector rho, 5 | real delta) { 6 | int N = size(x); 7 | matrix[N, N] K; 8 | real sq_alpha = square(alpha); 9 | for (i in 1:(N-1)) { 10 | K[i, i] = sq_alpha + delta; 11 | for (j in (i + 1):N) { 12 | K[i, j] = sq_alpha * exp(-0.5 * dot_self((x[i] - x[j]) ./ rho)); 13 | K[j, i] = K[i, j]; 14 | } 15 | } 16 | K[N, N] = sq_alpha + delta; 17 | return cholesky_decompose(K); 18 | } 19 | } 20 | data { 21 | int N; 22 | int D; 23 | vector[D] x[N]; 24 | vector[N] y; 25 | } 26 | transformed data { 27 | real delta = 1e-9; 28 | } 29 | parameters { 30 | vector[D] rho; 31 | real alpha; 32 | real sigma; 33 | vector[N] eta; 34 | } 35 | model { 36 | vector[N] f; 37 | { 38 | matrix[N, N] L_K = L_cov_exp_quad_ARD(x, alpha, rho, delta); 39 | f = L_K * eta; 40 | } 41 | rho ~ inv_gamma(5, 5); 42 | alpha ~ normal(0, 1); 43 | sigma ~ normal(0, 1); 44 | eta ~ normal(0, 1); 45 | y ~ normal(f, sigma); 46 | } -------------------------------------------------------------------------------- /tests/stan/ch21_oscillator.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int T; 3 | vector[2] y0; 4 | real ts[T]; 5 | real theta[1]; 6 | } 7 | model { 8 | } 9 | generated quantities { 10 | vector[2] y_hat[T]; 11 | matrix[2, 2] A = [[ 0, 1], 12 | [-1, -theta[1]]]; 13 | for (t in 1:T) 14 | y_hat[t] = matrix_exp((t - 1) * A) * y0; 15 | // add measurement error 16 | for (t in 1:T) { 17 | y_hat[t, 1] += normal_rng(0, 0.1); 18 | y_hat[t, 2] += normal_rng(0, 0.1); 19 | } 20 | } -------------------------------------------------------------------------------- /tests/stan/ch21_oscillator_2.stan: -------------------------------------------------------------------------------- 1 | functions { 2 | real[] sho(real t, 3 | real[] y, 4 | real[] theta, 5 | real[] x_r, 6 | int[] x_i) { 7 | real dydt[2]; 8 | dydt[1] = y[2]; 9 | dydt[2] = -y[1] - theta[1] * y[2]; 10 | return dydt; 11 | } 12 | } 13 | data { 14 | int T; 15 | real y0[2]; 16 | real t0; 17 | real ts[T]; 18 | real theta[1]; 19 | } 20 | transformed data { 21 | real x_r[0]; 22 | int x_i[0]; } 23 | model { 24 | } 25 | generated quantities { 26 | real y_hat[T,2] = integrate_ode_rk45(sho, y0, t0, ts, theta, x_r, x_i); 27 | // add measurement error 28 | for (t in 1:T) { 29 | y_hat[t, 1] += normal_rng(0, 0.1); 30 | y_hat[t, 2] += normal_rng(0, 0.1); 31 | } 32 | } -------------------------------------------------------------------------------- /tests/stan/ch21_oscillator_estimation.stan: -------------------------------------------------------------------------------- 1 | functions { 2 | real[] sho(real t, 3 | real[] y, 4 | real[] theta, 5 | real[] x_r, 6 | int[] x_i) { 7 | real dydt[2]; 8 | dydt[1] = y[2]; 9 | dydt[2] = -y[1] - theta[1] * y[2]; 10 | return dydt; 11 | } 12 | } 13 | data { 14 | int T; 15 | real y[T,2]; 16 | real t0; 17 | real ts[T]; 18 | } 19 | transformed data { 20 | real x_r[0]; 21 | int x_i[0]; } 22 | parameters { 23 | real y0[2]; 24 | vector[2] sigma; 25 | real theta[1]; 26 | } 27 | model { 28 | real y_hat[T,2]; 29 | sigma ~ cauchy(0, 2.5); 30 | theta ~ normal(0, 1); 31 | y0 ~ normal(0, 1); 32 | y_hat = integrate_ode_rk45(sho, y0, t0, ts, theta, x_r, x_i); 33 | for (t in 1:T) 34 | y[t] ~ normal(y_hat[t], sigma); 35 | } -------------------------------------------------------------------------------- /tests/stan/ch22_3_change.stan: -------------------------------------------------------------------------------- 1 | parameters { 2 | real y_inv; 3 | } 4 | transformed parameters { 5 | real y; 6 | y = 1 / y_inv; // change variables 7 | } 8 | model { 9 | y ~ gamma(2,4); 10 | target += -2 * log(y_inv); // Jacobian adjustment; 11 | } -------------------------------------------------------------------------------- /tests/stan/ch22_3_transform.stan: -------------------------------------------------------------------------------- 1 | parameters { 2 | real y; 3 | } 4 | transformed parameters { 5 | real y_inv; 6 | y_inv = 1 / y; 7 | } 8 | model { 9 | y ~ gamma(2,4); 10 | } 11 | -------------------------------------------------------------------------------- /tests/stan/ch23_1_triangle.stan: -------------------------------------------------------------------------------- 1 | parameters { 2 | real y; 3 | } 4 | model { 5 | target += log1m(fabs(y)); 6 | } -------------------------------------------------------------------------------- /tests/stan/ch24_1_relative_diff.stan: -------------------------------------------------------------------------------- 1 | functions { 2 | real relative_diff(real x, real y) { 3 | real abs_diff; 4 | real avg_scale; 5 | abs_diff = fabs(x - y); 6 | avg_scale = (fabs(x) + fabs(y)) / 2; 7 | return abs_diff / avg_scale; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/stan/ch24_2_function_as_statement.stan: -------------------------------------------------------------------------------- 1 | functions { 2 | void pretty_print_tri_lower(matrix x) { 3 | if (rows(x) == 0) { 4 | print("empty matrix"); 5 | return ; 6 | } 7 | print("rows=", rows(x), " cols=", cols(x)); 8 | for (m in 1:rows(x)) 9 | for (n in 1:m) 10 | print("[", m, ",", n, "]=", x[m, n]); 11 | } 12 | } -------------------------------------------------------------------------------- /tests/stan/ch25_fits1.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | real y[N]; 4 | } 5 | parameters { 6 | real lambda1; 7 | real lambda2; 8 | real sigma; 9 | } 10 | transformed parameters { 11 | real mu; 12 | mu = lambda1 + lambda2; 13 | } 14 | model { 15 | y ~ normal(mu, sigma); 16 | } 17 | -------------------------------------------------------------------------------- /tests/stan/ch25_fits2.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | real y[N]; 4 | } 5 | parameters { 6 | real mu; 7 | real sigma; 8 | } 9 | model { 10 | y ~ normal(mu, sigma); 11 | } 12 | -------------------------------------------------------------------------------- /tests/stan/ch28_11_standardizing_1.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | vector[N] y; 4 | vector[N] x; 5 | } 6 | parameters { 7 | real alpha; 8 | real beta; 9 | real sigma; 10 | } 11 | model { 12 | // priors 13 | alpha ~ normal(0, 10); 14 | beta ~ normal(0, 10); 15 | sigma ~ cauchy(0, 5); 16 | // likelihood 17 | for (n in 1:N) 18 | y[n] ~ normal(alpha + beta * x[n], sigma); 19 | } -------------------------------------------------------------------------------- /tests/stan/ch28_11_standardizing_2.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | vector[N] y; 4 | vector[N] x; 5 | } 6 | transformed data { 7 | vector[N] x_std; 8 | vector[N] y_std; 9 | x_std = (x - mean(x)) / sd(x); 10 | y_std = (y - mean(y)) / sd(y); 11 | } 12 | parameters { 13 | real alpha_std; 14 | real beta_std; 15 | real sigma_std; 16 | } 17 | model { 18 | alpha_std ~ normal(0, 10); 19 | beta_std ~ normal(0, 10); 20 | sigma_std ~ cauchy(0, 5); 21 | for (n in 1:N) 22 | y_std[n] ~ normal(alpha_std + beta_std * x_std[n], 23 | sigma_std); 24 | } 25 | generated quantities { 26 | real alpha; 27 | real beta; 28 | real sigma; 29 | alpha = sd(y) * (alpha_std - beta_std * mean(x) / sd(x)) 30 | + mean(y); 31 | beta = beta_std * sd(y) / sd(x); 32 | sigma = sd(y) * sigma_std; 33 | } 34 | -------------------------------------------------------------------------------- /tests/stan/ch28_8_bernoulli.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | int y[N]; 4 | real alpha; 5 | real beta; 6 | } 7 | parameters { 8 | real theta; 9 | } 10 | model { 11 | theta ~ beta(alpha, beta); 12 | for (n in 1:N) 13 | y[n] ~ bernoulli(theta); 14 | } 15 | -------------------------------------------------------------------------------- /tests/stan/ch28_neal_1.stan: -------------------------------------------------------------------------------- 1 | parameters { 2 | real y; 3 | vector[9] x; 4 | } 5 | model { 6 | y ~ normal(0, 3); 7 | x ~ normal(0, exp(y/2)); 8 | } 9 | -------------------------------------------------------------------------------- /tests/stan/ch28_neal_2.stan: -------------------------------------------------------------------------------- 1 | parameters { 2 | real y_raw; 3 | vector[9] x_raw; 4 | } 5 | transformed parameters { 6 | real y; 7 | vector[9] x; 8 | y = 3.0 * y_raw; 9 | x = exp(y/2) * x_raw; 10 | } 11 | model { 12 | y_raw ~ normal(0, 1); // implies y ~ normal(0, 3) 13 | x_raw ~ normal(0, 1); // implies x ~ normal(0, exp(y/2)) 14 | } 15 | -------------------------------------------------------------------------------- /tests/stan/ch28_vectorization_1.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int K; 3 | int N; 4 | real x[K, N]; 5 | real y[N]; 6 | } 7 | parameters { 8 | real beta[K]; 9 | } 10 | model { 11 | for (n in 1:N) { 12 | real gamma = 0; 13 | for (k in 1:K) 14 | gamma += x[n, k] * beta[k]; 15 | y[n] ~ normal(gamma, 1); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/stan/ch28_vectorization_2.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int K; 3 | int N; 4 | vector[K] x[N]; 5 | real y[N]; 6 | } 7 | parameters { 8 | vector[K] beta; 9 | } 10 | model { 11 | for (n in 1:N) 12 | y[n] ~ normal(dot_product(x[n], beta), 1); 13 | } 14 | -------------------------------------------------------------------------------- /tests/stan/ch28_vectorization_3.stan: -------------------------------------------------------------------------------- 1 | data { 2 | matrix[N, K] x; 3 | vector[N] y; 4 | } 5 | parameters { 6 | vector[K] beta; 7 | } 8 | model { 9 | y ~ normal(x * beta, 1); 10 | } 11 | -------------------------------------------------------------------------------- /tests/stan/ch28_vectorized_probability.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int K; 3 | int N; 4 | matrix[N, K] x; 5 | vector[N] y; 6 | } 7 | parameters { 8 | vector[K] beta; 9 | } 10 | model { 11 | y ~ normal(x * beta, 1); 12 | } 13 | -------------------------------------------------------------------------------- /tests/stan/ch31_square_error.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int N; 3 | int K; 4 | vector[N] y; 5 | matrix[N,K] x; 6 | } 7 | parameters { 8 | vector[K] beta; 9 | } 10 | transformed parameters { 11 | real squared_error; 12 | squared_error = dot_self(y - x * beta); 13 | } 14 | model { 15 | target += -squared_error; 16 | } 17 | generated quantities { 18 | real sigma_squared; 19 | sigma_squared = squared_error / N; 20 | } -------------------------------------------------------------------------------- /tests/stan/ch34_2_sampling.stan: -------------------------------------------------------------------------------- 1 | data { 2 | real theta; 3 | int K; 4 | int N; 5 | } 6 | model { 7 | } 8 | generated quantities { 9 | int y[N]; 10 | for (n in 1:N) 11 | y[n] = binomial_rng(K, theta); 12 | } 13 | -------------------------------------------------------------------------------- /tests/stan/coin.stan: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 IBM Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | data { 18 | int x[10]; 19 | } 20 | parameters { 21 | real theta; 22 | } 23 | model { 24 | theta ~ uniform(0.0,1.0); 25 | for (i in 1:10){ 26 | x[i] ~ bernoulli(theta); 27 | } 28 | print(x); 29 | } 30 | -------------------------------------------------------------------------------- /tests/stan/fun.stan: -------------------------------------------------------------------------------- 1 | functions { 2 | void f(int x); 3 | 4 | real id(real x) { 5 | return x; 6 | } 7 | } -------------------------------------------------------------------------------- /tests/stan/fundecl.stan: -------------------------------------------------------------------------------- 1 | functions { 2 | void sum(int[,] a) {} 3 | } 4 | model { 5 | } -------------------------------------------------------------------------------- /tests/stan/slice.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int d; 3 | matrix[d, d] d_m; 4 | } 5 | 6 | transformed data { 7 | vector[d] td = d_m[, 1]; 8 | } 9 | 10 | model { 11 | } 12 | -------------------------------------------------------------------------------- /tests/stan/slice2.stan: -------------------------------------------------------------------------------- 1 | data { 2 | int n_age; 3 | } 4 | 5 | transformed parameters { 6 | simplex[n_age + 1] pr_a; 7 | pr_a[n_age + 1] = 1 - sum(pr_a[:n_age]); 8 | } 9 | 10 | model { 11 | } -------------------------------------------------------------------------------- /tests/stan/slicstan.stan: -------------------------------------------------------------------------------- 1 | data{ 2 | int N; 3 | real y[N]; 4 | } 5 | parameters{ 6 | real mu; 7 | real tau; 8 | } 9 | transformed parameters{ 10 | real sigma = pow(tau,-0.5); 11 | } 12 | model{ 13 | tau ~ gamma(0.1,0.1); mu ~ normal(0,1); 14 | y ~ normal(mu,sigma); 15 | } 16 | generated quantities{ 17 | real v = pow(sigma,2); 18 | } 19 | -------------------------------------------------------------------------------- /tests/stan/test_stan.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 IBM Corporation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from pathlib import Path 16 | import yaps 17 | import pycmdstan 18 | import sys 19 | import tempfile 20 | import os 21 | 22 | 23 | def check_roundtrip(path): 24 | with open(path, 'r') as fin: 25 | code = fin.read() 26 | print(code) 27 | try: 28 | pycmdstan.model.preprocess_model(path, overwrite=True) 29 | try: 30 | source = yaps.from_stan(code_file=path) 31 | except (AttributeError, SyntaxError, TypeError, AssertionError, ValueError): 32 | assert False, 'Error: Stan2Yaps' 33 | try: 34 | stan = yaps.to_stan(source) 35 | except (AttributeError, SyntaxError, TypeError, AssertionError, ValueError): 36 | assert False, 'Error: Yaps2Stan' 37 | try: 38 | stan_file = tempfile.NamedTemporaryFile(suffix='.stan') 39 | stan_file.write(bytes(stan, 'utf-8')) 40 | stan_file.flush() 41 | pycmdstan.model.preprocess_model(stan_file.name) 42 | stan_file.close() 43 | except (AttributeError, SyntaxError, TypeError, AssertionError, ValueError): 44 | assert False, 'Error: Invalid Compiled Stan code' 45 | except (ValueError, RuntimeError): 46 | assert True, 'Error: Invalid Original Stan code' 47 | 48 | 49 | def test_stan(): 50 | pathlist = Path('tests/stan').glob('*.stan') 51 | for p in pathlist: 52 | path = str(p) 53 | print(path) 54 | yield check_roundtrip, path 55 | -------------------------------------------------------------------------------- /tests/stan/types.stan: -------------------------------------------------------------------------------- 1 | data { int AA[5]; matrix[5, 6] A[6]; 2 | matrix[5, 6] B[6]; 3 | matrix[5, 6] C[6, 7]; 4 | matrix[5, 6] D; 5 | simplex[5] E; 6 | } 7 | parameters { 8 | simplex[5] F[5, 6]; 9 | simplex[5] G; 10 | simplex[] H; 11 | int I[3]; 12 | int J; 13 | vector[12] K = {1,2,4,4,5,6,7,78}; 14 | int L[6]; 15 | real alpha; 16 | } -------------------------------------------------------------------------------- /tests/yaps/coin.py: -------------------------------------------------------------------------------- 1 | from yaps.lib import int, real, uniform, bernoulli 2 | import yaps as yaps 3 | import numpy as np 4 | 5 | 6 | @yaps.model 7 | def coin(x: int(lower=0, upper=1)[10]): 8 | theta: real(lower=0, upper=1) is uniform(0, 1) 9 | for i in range(1, 11): 10 | x[i] is bernoulli(theta) 11 | 12 | 13 | coin.graph 14 | print(coin) 15 | 16 | flips = np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 1]) 17 | 18 | constrained_coin = coin(x=flips) 19 | constrained_coin.sample(data=constrained_coin.data) 20 | theta_mean = constrained_coin.posterior.theta.mean() 21 | print("mean of theta: {:.3f}".format(theta_mean)) 22 | -------------------------------------------------------------------------------- /tests/yaps/coin_verbose.py: -------------------------------------------------------------------------------- 1 | import yaps as yaps 2 | from yaps.lib import int, real, parameters, model, uniform, bernoulli 3 | import numpy as np 4 | 5 | 6 | @yaps.model 7 | def coin(x: int(lower=0, upper=1)[10]): 8 | with parameters: 9 | theta: real(lower=0, upper=1) 10 | with model: 11 | theta < ~ uniform(0, 1) 12 | for i in range(1, 11): 13 | x[i] < ~ bernoulli(theta) 14 | 15 | 16 | print(coin) 17 | 18 | flips = np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 1]) 19 | 20 | constrained_coin = coin(x=flips) 21 | constrained_coin.sample(data=constrained_coin.data) 22 | theta_mean = constrained_coin.posterior.theta.mean() 23 | print("mean of theta: {:.3f}".format(theta_mean)) 24 | -------------------------------------------------------------------------------- /tests/yaps/regression.py: -------------------------------------------------------------------------------- 1 | from yaps.lib import * 2 | import yaps as yaps 3 | 4 | """ 5 | data { 6 | int N; 7 | vector[N] x; 8 | vector[N] y; 9 | } 10 | parameters { 11 | real alpha; 12 | real beta; 13 | real sigma; 14 | } 15 | model { 16 | y ~ normal(alpha + beta * x, sigma); 17 | } 18 | """ 19 | 20 | N = yaps.dependent_type_var() 21 | 22 | 23 | @yaps.model 24 | def regression(N: int(lower=0), x: vector[N], y: vector[N]): 25 | alpha: real 26 | beta: real 27 | sigma: real(lower=0) 28 | y is normal(alpha + beta * x, sigma) 29 | 30 | 31 | print(regression) 32 | -------------------------------------------------------------------------------- /tests/yaps/regression_bernoulli.py: -------------------------------------------------------------------------------- 1 | from yaps.lib import * 2 | import yaps as yaps 3 | 4 | """ 5 | data { 6 | int N; 7 | vector[N] x; 8 | int y[N]; 9 | } 10 | parameters { 11 | real alpha; 12 | real beta; 13 | } 14 | model { 15 | y ~ bernoulli_logit(alpha + beta * x); 16 | } 17 | """ 18 | 19 | N = yaps.dependent_type_var() 20 | 21 | 22 | @yaps.model 23 | def regression(N: int(lower=0), x: vector[N], y: vector(lower=0, upper=1)[N]): 24 | alpha: real 25 | beta: real 26 | y is bernoulli_logit(alpha + beta * x) 27 | 28 | 29 | print(regression) 30 | -------------------------------------------------------------------------------- /tests/yaps/regression_matrix.py: -------------------------------------------------------------------------------- 1 | from yaps.lib import * 2 | import yaps as yaps 3 | 4 | """ 5 | data { 6 | int N; 7 | int K; 8 | matrix[N, K] x; 9 | vector[N] y; 10 | } 11 | parameters { 12 | real alpha; 13 | vector[K] beta; 14 | real sigma; 15 | } 16 | model { 17 | y ~ normal(x * beta + alpha, sigma); 18 | } 19 | """ 20 | 21 | N = yaps.dependent_type_var() 22 | K = yaps.dependent_type_var() 23 | 24 | 25 | @yaps.model 26 | def regression(N: int(lower=0), K: int(lower=0), x: matrix[N, K], y: vector[N]): 27 | alpha: real 28 | beta: vector[K] 29 | sigma: real(lower=0) 30 | y is normal(x * beta + alpha, sigma) 31 | 32 | 33 | print(regression) 34 | -------------------------------------------------------------------------------- /tests/yaps/regression_qr.py: -------------------------------------------------------------------------------- 1 | from yaps.lib import * 2 | import yaps as yaps 3 | 4 | """ 5 | data { 6 | int N; 7 | int K; 8 | matrix[N, K] x; 9 | vector[N] y; 10 | } 11 | transformed data { 12 | matrix[N, K] Q_ast; 13 | matrix[K, K] R_ast; 14 | matrix[K, K] R_ast_inverse; 15 | // thin and scale the QR decomposition 16 | Q_ast = qr_Q(x)[, 1:K] * sqrt(N - 1); 17 | R_ast = qr_R(x)[1:K, ] / sqrt(N - 1); 18 | R_ast_inverse = inverse(R_ast); 19 | } 20 | parameters { 21 | real alpha; // intercept 22 | vector[K] theta; // coefficients on Q_ast 23 | real sigma; // error scale 24 | } 25 | model { 26 | y ~ normal(Q_ast * theta + alpha, sigma); // likelihood 27 | } 28 | generated quantities { 29 | vector[K] beta; 30 | beta = R_ast_inverse * theta; // coefficients on x 31 | } 32 | """ 33 | 34 | N = yaps.dependent_type_var() 35 | K = yaps.dependent_type_var() 36 | 37 | 38 | @yaps.model 39 | def regression(N: int(lower=0), K: int(lower=0), x: matrix[N, K], y: vector[N]): 40 | with transformed_data: 41 | Q_ast: matrix[N, K] 42 | R_ast: matrix[K, K] 43 | R_ast_inverse: matrix[K, K] 44 | Q_ast = qr_Q(x)[:, 1:K] * sqrt(N - 1) 45 | R_ast = qr_R(x)[1:K, :] / sqrt(N - 1) 46 | R_ast_inverse = inverse(R_ast) 47 | alpha: real 48 | theta: vector[K] 49 | sigma: real(lower=0) 50 | y is normal(Q_ast * theta + alpha, sigma) 51 | with generated_quantities: 52 | beta: vector[K] 53 | beta = R_ast_inverse * theta 54 | 55 | 56 | print(regression) 57 | -------------------------------------------------------------------------------- /tests/yaps/slicstan.py: -------------------------------------------------------------------------------- 1 | from yaps.lib import * 2 | import yaps as yaps 3 | 4 | N = yaps.dependent_type_var() 5 | 6 | 7 | @yaps.model 8 | def slicstan(N: int, y: real(lower=0, upper=1)[N]): 9 | tau: real is gamma(0.1, 0.1) 10 | mu: real is normal(0, 1) 11 | with transformed_parameters: 12 | sigma: real = pow(tau, -0.5) 13 | y is normal(mu, sigma) 14 | with generated_quantities: 15 | v: real = pow(sigma, 2) 16 | 17 | 18 | print(slicstan) 19 | -------------------------------------------------------------------------------- /tests/yaps/stan_types.py: -------------------------------------------------------------------------------- 1 | from yaps.lib import * 2 | import yaps as yaps 3 | 4 | 5 | N = type_var("N") 6 | 7 | 8 | @yaps.model 9 | def test(AA: int[5], 10 | A: matrix(lower=0)[5, 6][6], 11 | B: matrix[5, 6][6], 12 | C: matrix[5, 6][6, 7], 13 | D: matrix(lower=0)[5, 6], 14 | E: simplex[5]): 15 | F: simplex(lower=0)[5][5, 6] 16 | G: simplex[5] 17 | H: simplex(lower=0)[()] 18 | I: int(upper=5)[3] 19 | J: int(upper=5) 20 | K: int 21 | L: int[6] 22 | alpha: real 23 | 24 | 25 | print(test) 26 | -------------------------------------------------------------------------------- /tests/yaps/truncated.py: -------------------------------------------------------------------------------- 1 | from yaps.lib import * 2 | import yaps as yaps 3 | 4 | N = yaps.dependent_type_var() 5 | U = yaps.dependent_type_var() 6 | 7 | 8 | @yaps.model 9 | def truncature(N: int(lower=0), U: real, y: real(upper=U)[N]): 10 | mu: real 11 | sigma: real(lower=0) 12 | for n in range(1 - 1, N): 13 | y[n] is normal(mu, sigma).T[:, U] 14 | 15 | 16 | print(truncature) 17 | -------------------------------------------------------------------------------- /yaps/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 IBM Corporation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from . import lib 16 | from . import decorator 17 | from . import stan2yaps 18 | 19 | apply = lib.apply 20 | dependent_type_var = lib.dependent_type_var 21 | model = decorator.model 22 | 23 | from_stan = stan2yaps.from_stan 24 | to_stan = decorator.to_stan 25 | 26 | -------------------------------------------------------------------------------- /yaps/decorator.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 IBM Corporation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import functools 16 | import math 17 | import inspect as inspect 18 | import re as regex 19 | import sys 20 | from . import py2ir 21 | import pycmdstan 22 | import types 23 | from contextlib import redirect_stdout 24 | import io 25 | 26 | 27 | class Struct: 28 | def __init__(self, **entries): 29 | self.__dict__.update(entries) 30 | 31 | 32 | class model_with_args(object): 33 | def __init__(self, model, data): 34 | self.model = model 35 | self.stored_data = data 36 | 37 | def __call__(self, **kwargs): 38 | d = self.stored_data.copy() 39 | d.update(kwargs) 40 | return model_with_args(self.model, d) 41 | 42 | def __getattr__(self, name): 43 | cmdstan_model = pycmdstan.Model(code=str(self.model)) 44 | cmdstan_attr = getattr(cmdstan_model, name) 45 | if type(cmdstan_attr) == types.MethodType: 46 | def method(*args, **kwargs): 47 | f = io.StringIO() 48 | try: 49 | with redirect_stdout(f): 50 | result = cmdstan_attr(*args, **kwargs) 51 | self.posterior = Struct(**result.csv) 52 | except Exception as err: 53 | e = ValueError(self.map_valueerror(f.getvalue())) 54 | e.__traceback__ = err.__traceback__ 55 | raise e 56 | return method 57 | else: 58 | return getattr(cmdstan_model, name) 59 | 60 | def map_valueerror(self, err): 61 | fileName = inspect.getsourcefile(self.model.func) 62 | err = str(err) 63 | err = err.replace("'unknown file name'", "'" + fileName + "'") 64 | 65 | # 1->line, #2->col, #3->---, #4->code, #5->--- 66 | linecolre = regex.compile( 67 | "at line (\d+), column (\d+)[^-]*[^-]([-]{5,})[^-](.*)[^-]([-]{5,})", regex.MULTILINE | regex.DOTALL) 68 | 69 | def get_code(line, col): 70 | target_context_lines = 4 71 | 72 | py_source_lines, py_source_first_line = inspect.getsourcelines( 73 | self.model.func) 74 | context_lines = min(target_context_lines, len(py_source_lines)) 75 | prefix_lines = math.ceil(context_lines // 2) 76 | start_line = max(line - prefix_lines, 0) 77 | overhang = max(0, start_line + context_lines - 78 | len(py_source_lines)) 79 | start_line = max(0, start_line - overhang) 80 | 81 | ret = "" 82 | for lno in range(start_line, start_line+context_lines): 83 | cur_lineno = lno + py_source_first_line 84 | cur_line = py_source_lines[lno] 85 | ret += "{:>4}: {}".format(cur_lineno, cur_line) 86 | if lno == line: 87 | ret += " "*(col+6) + "^\n" 88 | return ret 89 | 90 | def mapLines(m): 91 | stan_line = int(m.group(1)) 92 | stan_col = int(m.group(2)) 93 | 94 | ir = self.source_map[stan_line-1][max(0, stan_col-2)] 95 | py_line = ir.lineno 96 | py_col = ir.col_offset 97 | 98 | py_source_lines, py_source_first_line = inspect.getsourcelines( 99 | self.model.func) 100 | py_code = get_code(py_line-1, py_col) 101 | if not py_code.endswith("\n"): 102 | py_code += "\n" 103 | return "at line {}, column {}\n{}\n{}{}\n".format(py_source_first_line+py_line-1, py_col+1, m.group(3), py_code, m.group(5)) 104 | 105 | err = linecolre.sub(mapLines, err) 106 | 107 | return err 108 | 109 | def apply(self, func, **kwargs): 110 | try: 111 | return func(model_code=self.model.stan_code, model_name=self.model.func.__name__, data=self.stored_data, **kwargs) 112 | except ValueError as err: 113 | e = ValueError(self.map_valueerror(str(err))) 114 | e.__traceback__ = err.__traceback__ 115 | raise e 116 | 117 | @property 118 | def graph(self): 119 | return self.model.graph 120 | 121 | @property 122 | def ir(self): 123 | return self.model.ir 124 | 125 | @property 126 | def source_map(self): 127 | return self.model.source_map 128 | 129 | @property 130 | def stan_code(self): 131 | return self.model.stan_code 132 | 133 | @property 134 | def data(self): 135 | return self.stored_data 136 | 137 | def __str__(self): 138 | return "stan:\n{}\ndata:\n{}".format(self.model, self.data) 139 | 140 | def __repr__(self): 141 | return self.model.__repr__ 142 | 143 | 144 | class model(object): 145 | def __init__(self, func): 146 | self.func = func 147 | functools.update_wrapper(self, func) 148 | self.compiled_model = py2ir.parse_function(func) 149 | self.model_string = self.compiled_model.to_mapped_string() 150 | self.viz = self.compiled_model.viz() 151 | 152 | def __call__(self, **kwargs): 153 | if kwargs: 154 | return model_with_args(self, kwargs) 155 | else: 156 | return self 157 | 158 | def infer(self, func, **kwargs): 159 | return model_with_args(self, {}).infer(func, **kwargs) 160 | 161 | @property 162 | def graph(self): 163 | return self.viz 164 | 165 | @property 166 | def ir(self): 167 | return self.compiled_model 168 | 169 | @property 170 | def source_map(self): 171 | return self.model_string 172 | 173 | @property 174 | def stan_code(self): 175 | return str(self) 176 | 177 | @property 178 | def data(self): 179 | return {} 180 | 181 | def __str__(self): 182 | return str(self.model_string) 183 | 184 | def __repr__(self): 185 | return self.func 186 | 187 | 188 | def print_stan(ir): 189 | return str(ir.to_mapped_string()) 190 | 191 | 192 | def to_stan(code_string=None, code_file=None): 193 | if not (code_string or code_file) or (code_string and code_file): 194 | assert False, "Either string or file but not both must be provided." 195 | if code_string: 196 | ast_ = py2ir.parse_string(code_string) 197 | else: 198 | with open(code_file, 'r') as file: 199 | code_string = file.read() 200 | ast_ = py2ir.parse_string(code_string) 201 | return print_stan(ast_) 202 | -------------------------------------------------------------------------------- /yaps/labeled_strings.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 IBM Corporation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | class LabeledString(object): 16 | def __init__(self, label, str): 17 | self.label = label 18 | self.str = str 19 | 20 | def __str__(self): 21 | return self.str 22 | 23 | 24 | class LineWithSourceMap(object): 25 | def __init__(self, line): 26 | self.line = line 27 | 28 | def __str__(self): 29 | return ''.join(map(lambda x: x.str, self.line)) 30 | 31 | def __getitem__(self, i): 32 | curIndex = 0 33 | curChar = 0 34 | while curIndex < len(self.line): 35 | elem = self.line[curIndex] 36 | curChar += len(elem.str) 37 | if i < curChar: 38 | return elem.label 39 | curIndex += 1 40 | # If it is past the end of the line, just blame the last element 41 | if self.line: 42 | return self.line[-1].label 43 | 44 | 45 | class StringWithSourceMap(object): 46 | def __init__(self, lines, lastData): 47 | self.lines = [] 48 | for l in lines: 49 | self.lines.append(LineWithSourceMap(l)) 50 | self.lines.append(LineWithSourceMap(lastData)) 51 | 52 | def __str__(self): 53 | return '\n'.join(map(str, self.lines)) 54 | 55 | def __getitem__(self, i): 56 | return self.lines[i] 57 | 58 | 59 | class LabeledRope(object): 60 | def __init__(self, strings=[]): 61 | self.lines = [] 62 | self.lastLine = [] 63 | self.lastLine.extend(strings) 64 | 65 | def append(self, x): 66 | self.lastLine.append(x) 67 | 68 | def extend(self, x): 69 | self.lastLine.extend(x) 70 | 71 | def __iadd__(self, x): 72 | self.append(x) 73 | return self 74 | 75 | def newline(self): 76 | self.lines.append(self.lastLine) 77 | self.lastLine = [] 78 | 79 | def result(self): 80 | return StringWithSourceMap(self.lines, self.lastLine) 81 | 82 | def __str__(self): 83 | return str(self.result()) 84 | -------------------------------------------------------------------------------- /yaps/lib.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 IBM Corporation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | def apply(func, model, *args, **kwargs): 17 | return model.apply(func, *args, **kwargs) 18 | 19 | # Types 20 | 21 | 22 | class dummy_full_type(object): 23 | def __init__(self, name): 24 | self.name = name 25 | 26 | def __call__(self, *args, **kwargs): 27 | raise TypeError("{} cannot be further constrained".format(self.name)) 28 | 29 | def __getitem__(self, key): 30 | raise TypeError( 31 | "{} cannot have additional dimensions".format(self.name)) 32 | 33 | def print_dims(self, key): 34 | if type(key) is tuple: 35 | ret = "" 36 | first = True 37 | for i in key: 38 | if first: 39 | first = False 40 | else: 41 | ret += ", " 42 | ret += str(i) 43 | return ret 44 | else: 45 | return str(key) 46 | 47 | 48 | class dummy_constrained_type(dummy_full_type): 49 | def __init__(self, name): 50 | dummy_full_type.__init__(self, name) 51 | 52 | def __getitem__(self, key): 53 | return dummy_full_type("{}[{}]".format(self.name, self.print_dims(key))) 54 | 55 | 56 | class dummy_type(dummy_constrained_type): 57 | def __init__(self, name): 58 | dummy_constrained_type.__init__(self, name) 59 | 60 | def __call__(self, *args, **kwargs): 61 | return dummy_constrained_type(self.name) 62 | 63 | 64 | class dummy_constrained_dim_type(dummy_full_type): 65 | def __init__(self, name, num_args): 66 | dummy_full_type.__init__(self, name) 67 | self.num_args = num_args 68 | 69 | def __getitem__(self, key): 70 | if self.num_args == 1: 71 | if key is tuple: 72 | raise TypeError("{} was given {} dimensions; {} expected".format( 73 | self.name, len(key), self.num_args)) 74 | else: 75 | return dummy_constrained_type("{}[{}]".format(self.name, self.print_dims(key))) 76 | else: 77 | if type(key) is tuple: 78 | if len(key) == self.num_args: 79 | return dummy_constrained_type("{}[{}]".format(self.name, self.print_dims(key))) 80 | else: 81 | raise TypeError("{} was given {} dimensions; {} expected".format( 82 | self.name, len(key), self.num_args)) 83 | else: 84 | raise TypeError("{} was given {} dimensions; {} expected".format( 85 | self.name, 1, self.num_args)) 86 | 87 | # vector/matrix types. They must be applied to a dimension 88 | 89 | 90 | class dummy_dim_type(dummy_constrained_dim_type): 91 | def __init__(self, name, num_args): 92 | dummy_constrained_dim_type.__init__(self, name, num_args) 93 | 94 | def __call__(self, *args, **kwargs): 95 | return dummy_constrained_dim_type(self.name, self.num_args) 96 | 97 | 98 | int = dummy_type("int") 99 | real = dummy_type("real") 100 | 101 | vector = dummy_dim_type("vector", 1) 102 | simplex = dummy_dim_type("simplex", 1) 103 | unit_vector = dummy_dim_type("unit_vector", 1) 104 | ordered = dummy_dim_type("ordered", 1) 105 | positive_ordered = dummy_dim_type("positive_ordered", 1) 106 | row_vector = dummy_dim_type("row_vector", 1) 107 | 108 | 109 | matrix = dummy_dim_type("matrix", 2) 110 | corr_matrix = dummy_dim_type("corr_matrix", 1) 111 | cholesky_factor_corr = dummy_dim_type("cholesky_factor_corr", 1) 112 | cov_matrix = dummy_dim_type("cov_matrix", 1) 113 | cholesky_factor_cov = dummy_dim_type("cholesky_factor_cov", 1) 114 | 115 | type_var = dummy_type 116 | dependent_type_var = type_var("type_var") 117 | 118 | # Blocks 119 | 120 | 121 | class block(object): 122 | def __enter__(self): 123 | pass 124 | 125 | def __exit__(self, x, y, z): 126 | pass 127 | 128 | 129 | class functions(object): 130 | def __enter__(self): 131 | pass 132 | 133 | def __exit__(self, x, y, z): 134 | pass 135 | 136 | 137 | class data(object): 138 | def __enter__(self): 139 | pass 140 | 141 | def __exit__(self, x, y, z): 142 | pass 143 | 144 | 145 | class transformed_data(object): 146 | def __enter__(self): 147 | pass 148 | 149 | def __exit__(self, x, y, z): 150 | pass 151 | 152 | 153 | class parameters(object): 154 | def __enter__(self): 155 | pass 156 | 157 | def __exit__(self, x, y, z): 158 | pass 159 | 160 | 161 | class transformed_parameters(object): 162 | def __enter__(self): 163 | pass 164 | 165 | def __exit__(self, x, y, z): 166 | pass 167 | 168 | 169 | class model(object): 170 | def __enter__(self): 171 | pass 172 | 173 | def __exit__(self, x, y, z): 174 | pass 175 | 176 | 177 | class generated_quantities(object): 178 | def __enter__(self): 179 | pass 180 | 181 | def __exit__(self, x, y, z): 182 | pass 183 | 184 | 185 | # Distributions 186 | 187 | 188 | def uniform(x, y): 189 | pass 190 | 191 | 192 | def bernoulli(p): 193 | pass 194 | 195 | 196 | def bernoulli_logit(p): 197 | pass 198 | 199 | 200 | def gamma(x, y): 201 | pass 202 | 203 | 204 | def normal(x, y): 205 | pass 206 | 207 | 208 | # Functions 209 | 210 | def pmult(x, y): 211 | return x 212 | 213 | 214 | def pdiv(x, y): 215 | return x 216 | 217 | 218 | def qr_Q(x): 219 | return x 220 | 221 | 222 | def qr_R(x): 223 | return x 224 | 225 | 226 | def inverse(x): 227 | return x 228 | 229 | 230 | def sqrt(x): 231 | return x 232 | -------------------------------------------------------------------------------- /yaps/py2ir.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 IBM Corporation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import ast 16 | import inspect 17 | from . import ir as IR 18 | import astor 19 | import re 20 | 21 | 22 | class PythonVisitor(ast.NodeVisitor): 23 | def __init__(self): 24 | self.functions = [] 25 | self.data = [] 26 | self.transformed_data = [] 27 | self.parameters = [] 28 | self.transformed_parameters = [] 29 | self.model = [] 30 | self.generated_quantities = [] 31 | 32 | def generic_visit(self, node): 33 | kind = type(node).__name__ 34 | print("Missing visit method for {}".format(kind)) 35 | raise SyntaxError 36 | 37 | def visit_list(self, list): 38 | res = [] 39 | for item in list: 40 | res.append(self.visit(item)) 41 | return res 42 | 43 | # Stan specifics 44 | def visit_Module(self, node): 45 | assert len(node.body) == 1 46 | model = node.body[0] 47 | assert isinstance(model, ast.FunctionDef), 'Model must be FunctionDecl' 48 | self.visit_Model(model) 49 | return IR.Program({ 50 | "functions": IR.FunctionsBlock(self.functions), 51 | "data": IR.DataBlock(self.data), 52 | "transformed_data": IR.TransformedDataBlock(self.transformed_data), 53 | "parameters": IR.ParametersBlock(self.parameters), 54 | "transformed_parameters": IR.TransformedParametersBlock(self.transformed_parameters), 55 | "generated_quantities": IR.GeneratedQuantities(self.generated_quantities), 56 | "model": IR.ModelBlock(self.model), 57 | }) 58 | 59 | def visit_Model(self, node): 60 | for arg in node.args.args: 61 | self.visit_DataDecl(arg) 62 | for stmt in node.body: 63 | if isinstance(stmt, ast.With): 64 | self.visit_Block(stmt) 65 | elif isinstance(stmt, ast.AnnAssign): 66 | self.visit_parameter(stmt) 67 | elif isinstance(stmt, ast.FunctionDef): 68 | self.functions.append(self.visit(stmt)) 69 | elif not isinstance(stmt, ast.Pass): 70 | self.model.append(self.visit(stmt)) 71 | 72 | def visit_Block(self, node): 73 | assert len(node.items) == 1 74 | kind = node.items[0].context_expr.id 75 | if kind == 'functions': 76 | for stmt in node.body: 77 | f = self.visit(stmt) 78 | self.functions.append(f) 79 | elif kind == 'data': 80 | for stmt in node.body: 81 | data = self.visit(stmt) 82 | self.data.append(data) 83 | elif kind == 'transformed_data': 84 | for stmt in node.body: 85 | self.transformed_data.append(self.visit(stmt)) 86 | elif kind == 'parameters': 87 | for stmt in node.body: 88 | param = self.visit(stmt) 89 | self.parameters.append(param) 90 | elif kind == 'transformed_parameters': 91 | for stmt in node.body: 92 | self.transformed_parameters.append(self.visit(stmt)) 93 | elif kind == 'model': 94 | for stmt in node.body: 95 | self.model.append(self.visit(stmt)) 96 | elif kind == 'generated_quantities': 97 | for stmt in node.body: 98 | self.generated_quantities.append(self.visit(stmt)) 99 | elif kind == 'block': 100 | self.model.append(self.visit(node)) 101 | else: 102 | assert False, 'Unknown block statement' 103 | 104 | def visit_DataDecl(self, node): 105 | id = node.arg 106 | ty = self.visit_datatype(node.annotation) 107 | self.data.append(IR.VariableDecl(id, ty).set_map(node)) 108 | 109 | def visit_parameter(self, node): 110 | id = node.target.id 111 | type_ast = node.annotation 112 | if isinstance(type_ast, ast.Compare): 113 | assert len(type_ast.ops) == 1 114 | assert isinstance(type_ast.ops[0], ast.Is) 115 | assert len(type_ast.comparators) == 1 116 | ty = self.visit_datatype(type_ast.left) 117 | self.parameters.append(IR.VariableDecl(id, ty).set_map(node)) 118 | dist, trunc = self.visit_distribution(type_ast.comparators[0]) 119 | self.model.append(IR.SamplingStmt( 120 | IR.Variable(id), dist, trunc).set_map(node)) 121 | else: 122 | ty = self.visit_datatype(node.annotation) 123 | self.parameters.append(IR.VariableDecl(id, ty).set_map(node)) 124 | 125 | def visit_distribution(self, node): 126 | if isinstance(node, ast.Subscript): 127 | assert isinstance(node.value, ast.Attribute) 128 | assert node.value.attr == 'T' 129 | dist = self.visit(node.value.value) 130 | trunc = self.visit(node.slice) 131 | return dist, trunc 132 | else: 133 | return self.visit(node), None 134 | 135 | def visit_Attribute(self, node): 136 | assert node.attr == 'transpose', "We only support the transpose attribute" 137 | val = self.visit(node.value) 138 | return IR.Transpose(val) 139 | 140 | def visit_type(self, node): 141 | kind = None 142 | dims = None 143 | 144 | n = node 145 | 146 | if isinstance(n, ast.Subscript): 147 | dims = self.visit(n.slice.value) 148 | n = n.value 149 | 150 | if isinstance(n, ast.Name): 151 | kind = n.id 152 | else: 153 | assert False, 'Wrong type format' 154 | return IR.Type(kind, dims) 155 | 156 | def visit_datatype(self, node): 157 | kind = None 158 | cstrts = [] 159 | dims = None 160 | inner_dims = None 161 | if isinstance(node, ast.Subscript): 162 | dims = self.visit(node.slice.value) 163 | type_ast = node.value 164 | if isinstance(type_ast, ast.Subscript): 165 | inner_dims = self.visit(type_ast.slice.value) 166 | type_ast = type_ast.value 167 | else: 168 | type_ast = node 169 | if isinstance(type_ast, ast.Name): 170 | kind = type_ast.id 171 | elif isinstance(type_ast, ast.Call): 172 | kind = type_ast.func.id 173 | for c in type_ast.keywords: 174 | cstrts.append(self.visit_constraint(c)) 175 | else: 176 | assert False, 'Wrong data type format' 177 | 178 | if kind in ["int", "real"]: 179 | assert not inner_dims, ('Wrong data type format {} does not take a dimension'.format( 180 | kind)) 181 | t = IR.AtomicDataType(kind, cstrts) 182 | if dims: 183 | return IR.ArrayDataType(t, dims) 184 | else: 185 | return t 186 | else: 187 | assert dims, ('Wrong data type format; {} requires a dimension'.format( 188 | kind)) 189 | 190 | if inner_dims: 191 | return IR.ArrayDataType(IR.DimDataType(kind, inner_dims, cstrts), dims) 192 | else: 193 | return IR.DimDataType(kind, dims, cstrts) 194 | 195 | def visit_constraint(self, node): 196 | lhs = node.arg 197 | rhs = self.visit(node.value) 198 | return lhs, rhs 199 | 200 | # Python visitor 201 | def visit_FunctionDef(self, node): 202 | id = node.name 203 | ty = self.visit_type(node.returns) 204 | args = [] 205 | for a in node.args.args: 206 | args.append(self.visit(a)) 207 | body = [] 208 | for stmt in node.body: 209 | s = self.visit(stmt) 210 | # Required because visit_Pass is not working 211 | if s is not None: 212 | body.append(s) 213 | return IR.FunctionDef(id, args, ty, body) 214 | 215 | def visit_arg(self, node): 216 | id = node.arg 217 | ty = self.visit_type(node.annotation) 218 | return IR.Arg(id, ty).set_map(node) 219 | 220 | def visit_Assign(self, node): 221 | assert len(node.targets) == 1 222 | lhs = self.visit(node.targets[0]) 223 | rhs = self.visit(node.value) 224 | return IR.AssignStmt(lhs, None, rhs).set_map(node) 225 | 226 | def visit_AnnAssign(self, node): 227 | assert node.simple == 1 228 | id = node.target.id 229 | ty = self.visit_datatype(node.annotation) 230 | val = self.visit(node.value) 231 | return IR.VariableDecl(id, ty, val).set_map(node) 232 | 233 | def visit_AugAssign(self, node): 234 | lhs = self.visit(node.target) 235 | rhs = self.visit(node.value) 236 | return IR.AugAssignStmt(lhs, rhs).set_map(node) 237 | 238 | def visit_For(self, node): 239 | var = self.visit(node.target) 240 | iter = self.visit(node.iter) 241 | body = self.visit(node.body) 242 | return IR.ForStmt(var, iter, body).set_map(node) 243 | 244 | def visit_While(self, node): 245 | test = self.visit(node.test) 246 | body = self.visit(node.body) 247 | return IR.WhileStmt(test, body) 248 | 249 | def visit_If(self, node): 250 | cond = self.visit(node.test) 251 | exp = self.visit(node.body) 252 | alt = self.visit(node.orelse) 253 | return IR.ConditionalStmt(cond, exp, alt).set_map(node) 254 | 255 | def visit_With(self, node): 256 | body = self.visit(node.body) 257 | return IR.Block(body) 258 | 259 | def visit_Continue(self, node): 260 | return IR.ContinueStmt() 261 | 262 | def visit_Break(self, node): 263 | return IR.BreakStmt() 264 | 265 | def visit_Pass(self, node): 266 | return IR.PassStmt() 267 | 268 | def visit_Return(self, node): 269 | val = self.visit(node.value) 270 | return IR.ReturnStmt(val) 271 | 272 | def visit_Expr(self, node): 273 | body = self.visit(node.value) 274 | # `is` (ast.Compare) is used for the sampling statement 275 | if isinstance(node.value, ast.Compare): 276 | return body 277 | else: 278 | return IR.ExprStmt(body) 279 | 280 | def visit_Num(self, node): 281 | return IR.Constant(node.n).set_map(node) 282 | 283 | def visit_Name(self, node): 284 | return IR.Variable(node.id).set_map(node) 285 | 286 | def visit_NoneType(self, node): 287 | return None 288 | 289 | def visit_Tuple(self, node): 290 | elts = [] 291 | for e in node.elts: 292 | elts.append(self.visit(e)) 293 | return IR.Tuple(elts) 294 | 295 | def visit_List(self, node): 296 | elts = [] 297 | for e in node.elts: 298 | elts.append(self.visit(e)) 299 | return IR.List(elts) 300 | 301 | def visit_Set(self, node): 302 | elts = [] 303 | for e in node.elts: 304 | elts.append(self.visit(e)) 305 | return IR.Set(elts) 306 | 307 | def visit_Str(self, node): 308 | return IR.Constant(node.s).set_map(node) 309 | 310 | def visit_Slice(self, node): 311 | assert not node.step, "slices with a step not currently supported" 312 | lower = None 313 | upper = None 314 | if node.lower: 315 | lower = self.visit(node.lower) 316 | if node.upper: 317 | upper = self.visit(node.upper) 318 | return IR.Slice(lower, upper).set_map(node) 319 | 320 | def visit_ExtSlice(self, node): 321 | dims = [] 322 | for e in node.dims: 323 | dims.append(self.visit(e)) 324 | return IR.Tuple(dims).set_map(node) 325 | 326 | def visit_Subscript(self, node): 327 | val = self.visit(node.value) 328 | slice = self.visit(node.slice) 329 | return IR.Subscript(val, slice).set_map(node) 330 | 331 | def visit_Index(self, node): 332 | return self.visit(node.value) 333 | 334 | def visit_Call(self, node): 335 | args = self.visit(node.args) 336 | if isinstance(node.func, ast.Name): 337 | id = node.func.id 338 | return IR.Call(id, args).set_map(node) 339 | elif isinstance(node.func, ast.Attribute): 340 | assert len(args) == 1, 'Wrong number of arguments' 341 | e2 = args[0] 342 | e1 = self.visit(node.func.value) 343 | if node.func.attr == 'pmult': 344 | return IR.Binop(IR.PMULT(), e1, e2) 345 | elif node.func.attr == 'pdiv': 346 | return IR.Binop(IR.PDIV(), e1, e2) 347 | else: 348 | assert False, 'Unsupported attribute method' 349 | else: 350 | assert False, 'Unsupported function call' 351 | 352 | def visit_Compare(self, node): 353 | # No chaining 354 | assert len(node.ops) == 1 355 | assert len(node.comparators) == 1 356 | op = node.ops[0] 357 | lhs = self.visit(node.left) 358 | # Is is the sampling operator 359 | if isinstance(op, ast.Is): 360 | dist, trunc = self.visit_distribution(node.comparators[0]) 361 | return IR.SamplingStmt(lhs, dist, trunc).set_map(node) 362 | else: 363 | rhs = self.visit(node.comparators[0]) 364 | op = self.visit(op) 365 | return IR.Binop(op, lhs, rhs).set_map(node) 366 | 367 | def visit_IfExp(self, node): 368 | test = self.visit(node.test) 369 | body = self.visit(node.body) 370 | orelse = self.visit(node.orelse) 371 | return IR.IfExp(test, body, orelse).set_map(node) 372 | 373 | def visit_BinOp(self, node): 374 | op = self.visit(node.op) 375 | lhs = self.visit(node.left) 376 | rhs = self.visit(node.right) 377 | return IR.Binop(op, lhs, rhs).set_map(node) 378 | 379 | def visit_UnaryOp(self, node): 380 | op = self.visit(node.op) 381 | expr = self.visit(node.operand) 382 | return IR.Unop(op, expr).set_map(node) 383 | 384 | def visit_BoolOp(self, node): 385 | op = self.visit(node.op) 386 | values = [] 387 | for e in node.values: 388 | values.append(self.visit(e)) 389 | return IR.Boolop(op, values) 390 | 391 | def visit_NameConstant(self, node): 392 | if node.value == True: 393 | return IR.Constant("true") 394 | elif node.value == False: 395 | return IR.Constant("true") 396 | else: 397 | assert False, 'None is not supported' 398 | 399 | def visit_USub(self, node): 400 | return IR.SUB() 401 | 402 | def visit_UAdd(self, node): 403 | return IR.ADD() 404 | 405 | def visit_Sub(self, node): 406 | return IR.SUB() 407 | 408 | def visit_Add(self, node): 409 | return IR.ADD() 410 | 411 | def visit_Mult(self, node): 412 | return IR.MULT() 413 | 414 | def visit_Div(self, node): 415 | return IR.DIV() 416 | 417 | def visit_Pow(self, node): 418 | return IR.POW() 419 | 420 | def visit_Mod(self, node): 421 | return IR.MOD() 422 | 423 | def visit_BitOr(self, node): 424 | return IR.MID() 425 | 426 | def visit_Eq(self, node): 427 | return IR.EQ() 428 | 429 | def visit_NotEq(self, node): 430 | return IR.NEQ() 431 | 432 | def visit_Lt(self, node): 433 | return IR.LT() 434 | 435 | def visit_LtE(self, node): 436 | return IR.LEQ() 437 | 438 | def visit_Gt(self, node): 439 | return IR.GT() 440 | 441 | def visit_GtE(self, node): 442 | return IR.GEQ() 443 | 444 | def visit_And(self, node): 445 | return IR.AND() 446 | 447 | def visit_Or(self, node): 448 | return IR.OR() 449 | 450 | def visit_Not(self, node): 451 | return IR.NOT() 452 | 453 | 454 | def parse_string(s): 455 | # Hack to avoid weird AST with sampling op 456 | source = re.sub(r"<\s*~", "is", s, re.X) 457 | tree = ast.parse(source) 458 | visitor = PythonVisitor() 459 | return visitor.visit(tree) 460 | 461 | 462 | def parse_function(model): 463 | source = inspect.getsource(model) 464 | return parse_string(source) 465 | -------------------------------------------------------------------------------- /yaps/roundtrip.py: -------------------------------------------------------------------------------- 1 | from . import stan2yaps 2 | from . import decorator 3 | import sys 4 | 5 | def roundtrip(code_file=None): 6 | with open(code_file, 'r') as file: 7 | code_string = file.read() 8 | print(code_string) 9 | print('# -------------') 10 | source = stan2yaps.from_stan(code_string) 11 | print(source) 12 | print('# -------------') 13 | target = decorator.to_stan(code_string=source) 14 | print(target) 15 | 16 | def main(): 17 | if (len(sys.argv) <= 1): 18 | assert False, "File name expected" 19 | for i in range(1, len(sys.argv)): 20 | print('# -------------') 21 | print('#', sys.argv[i]) 22 | print('# -------------') 23 | roundtrip(code_file=sys.argv[i]) -------------------------------------------------------------------------------- /yaps/stan.g4: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 IBM Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | grammar stan; 18 | 19 | /** Includes (section 2.2) */ 20 | 21 | include 22 | : '#' 'include' IDENTIFIER '.' IDENTIFIER 23 | ; 24 | 25 | 26 | /** Comments (section 2.3) */ 27 | 28 | COMMENT 29 | : '/*' .*? '*/' -> channel(3) // COMMENTS 30 | ; 31 | 32 | LINE_COMMENT 33 | : '//' ~[\r\n]* -> channel(3) //COMMENTS 34 | ; 35 | 36 | 37 | /** Whitespaces (section 2.4) */ 38 | 39 | WS : [ \t\r\n\u000C]+ -> channel(1) // WHITESPACES 40 | ; 41 | 42 | /** Numeric literals (section 4.1) */ 43 | 44 | IntegerLiteral 45 | : DecimalNumeral 46 | ; 47 | 48 | RealLiteral: 49 | Digits '.' Digits? ExponentPart? 50 | | '.' Digits ExponentPart? 51 | | Digits ExponentPart 52 | ; 53 | 54 | fragment 55 | ExponentPart: 56 | ('e'|'E') ('+'|'-')? Digits 57 | ; 58 | 59 | fragment 60 | DecimalNumeral 61 | : '0' 62 | | NonZeroDigit Digits? 63 | ; 64 | 65 | fragment 66 | Digits 67 | : Digit+ 68 | ; 69 | 70 | fragment 71 | Digit 72 | : '0' 73 | | NonZeroDigit 74 | ; 75 | 76 | fragment 77 | NonZeroDigit 78 | : [1-9] 79 | ; 80 | 81 | StringLiteral 82 | :'"' (~["\r\n])* '"' 83 | ; 84 | 85 | /** Variables and keywords (section 4.2) */ 86 | 87 | /* Keywords */ 88 | FOR: 'for'; 89 | IN: 'in'; 90 | WHILE: 'while'; 91 | REPEAT: 'repeat'; 92 | UNTIL: 'until'; 93 | IF: 'if'; 94 | THEN: 'then'; 95 | ELSE: 'else'; 96 | TRUE: 'true'; 97 | FALSE: 'false'; 98 | 99 | /* Type names */ 100 | INT: 'int'; 101 | REAL: 'real'; 102 | VECTOR: 'vector'; 103 | SIMPLEX: 'simplex'; 104 | ORDERED: 'ordered'; 105 | POSITIVE_ORDERED: 'positive_ordered'; 106 | ROW_VECTOR: 'row_vector'; 107 | UNIT_VECTOR: 'unit_vector'; 108 | MATRIX: 'matrix'; 109 | CHOLESKY_FACTOR_CORR: 'cholesky_factor_corr'; 110 | CHOLESKY_FACTOR_COV: 'cholesky_factor_cov'; 111 | CORR_MATRIX: 'corr_matrix'; 112 | COV_MATRIX: 'cov_matrix'; 113 | 114 | /* Block identifiers */ 115 | FUNCTIONS: 'functions'; 116 | MODEL: 'model'; 117 | DATA: 'data'; 118 | PARAMETERS: 'parameters'; 119 | QUANTITIES: 'quantities'; 120 | TRANSFORMED: 'transformed'; 121 | GENERATED: 'generated'; 122 | 123 | /* Reserved Names from Stan Implementation */ 124 | VAR: 'var'; 125 | FVAR: 'fvar'; 126 | STAN_MAJOR: 'STAN_MAJOR'; 127 | STAN_MINOR: 'STAN_MINOR'; 128 | STAN_PATCH: 'STAN_PATCH'; 129 | STAN_MATH_MAJOR: 'STAN_MATH_MAJOR'; 130 | STAN_MATH_MINOR: 'STAN_MATH_MINOR'; 131 | STAN_MATH_PATCH: 'STAN_MATH_PATCH'; 132 | 133 | /* Reserved Names from C++ */ 134 | ALIGNAS: 'alignas'; 135 | ALIGNOF: 'alignof'; 136 | AND: 'and'; 137 | AND_EQ: 'and_eq'; 138 | ASM: 'asm'; 139 | AUTO: 'auto'; 140 | BITAND: 'bitand'; 141 | BITOR: 'bitor'; 142 | BOOL: 'bool'; 143 | BREAK: 'break'; 144 | CASE: 'case'; 145 | CATCH: 'catch'; 146 | CHAR: 'char'; 147 | CHAR16_T: 'char16_t'; 148 | CHAR32_T: 'char32_t'; 149 | CLASS: 'class'; 150 | COMPL: 'compl'; 151 | CONST: 'const'; 152 | CONSTEXPR: 'constexpr'; 153 | CONST_CAST: 'const_cast'; 154 | CONTINUE: 'continue'; 155 | DECLTYPE: 'decltype'; 156 | DEFAULT: 'default'; 157 | DELETE: 'delete'; 158 | DO: 'do'; 159 | DOUBLE: 'double'; 160 | DYNAMIC_CAST: 'dynamic_cast'; 161 | ENUM: 'enum'; 162 | EXPLICIT: 'explicit'; 163 | EXPORT: 'export'; 164 | EXTERN: 'extern'; 165 | FLOAT: 'float'; 166 | FRIEND: 'friend'; 167 | GOTO: 'goto'; 168 | INLINE: 'inline'; 169 | LONG: 'long'; 170 | MUTABLE: 'mutable'; 171 | NAMESPACE: 'namespace'; 172 | NEW: 'new'; 173 | NOEXCEPT: 'noexcept'; 174 | NOT: 'not'; 175 | NOT_EQ: 'not_eq'; 176 | NULLPTR: 'nullptr'; 177 | OPERATOR: 'operator'; 178 | OR: 'or'; 179 | OR_EQ: 'or_eq'; 180 | PRIVATE: 'private'; 181 | PROTECTED: 'protected'; 182 | PUBLIC: 'public'; 183 | REGISTER: 'register'; 184 | REINTERPRET_CAST: 'reinterpret_cast'; 185 | RETURN: 'return'; 186 | SHORT: 'short'; 187 | SIGNED: 'signed'; 188 | SIZEOF: 'sizeof'; 189 | STATIC: 'static'; 190 | STATIC_ASSERT: 'static_assert'; 191 | STATIC_CAST: 'static_cast'; 192 | STRUCT: 'struct'; 193 | SWITCH: 'switch'; 194 | TEMPLATE: 'template'; 195 | THIS: 'this'; 196 | THREAD_LOCAL: 'thread_local'; 197 | THROW: 'throw'; 198 | TRY: 'try'; 199 | TYPEDEF: 'typedef'; 200 | TYPEID: 'typeid'; 201 | TYPENAME: 'typename'; 202 | UNION: 'union'; 203 | UNSIGNED: 'unsigned'; 204 | USING: 'using'; 205 | VIRTUAL: 'virtual'; 206 | VOID: 'void'; 207 | VOLATILE: 'volatile'; 208 | WCHAR_T: 'wchar_t'; 209 | XOR: 'xor'; 210 | XOR_EQ: 'xor_eq'; 211 | 212 | 213 | /* Variables */ 214 | 215 | BAD_IDENTIFIER 216 | : [a-zA-Z] [a-zA-Z0-9_]* '__' 217 | ; 218 | 219 | IDENTIFIER 220 | : [a-zA-Z] [a-zA-Z0-9_]* 221 | ; 222 | 223 | 224 | /* Operators (figure 4.1) */ 225 | 226 | OR_OP: '||'; 227 | AND_OP: '&&'; 228 | EQ_OP: '=='; 229 | NEQ_OP: '!='; 230 | LT_OP: '<'; 231 | LE_OP: '<='; 232 | GT_OP: '>'; 233 | GE_OP: '>='; 234 | PLUS_OP: '+'; 235 | MINUS_OP: '-'; 236 | MULT_OP: '*'; 237 | DIV_OP: '/'; 238 | MOD_OP: '%'; 239 | LEFT_DIV_OP: '\\'; 240 | DOT_MULT_OP: '.*'; 241 | DOT_DIV_OP: './'; 242 | NOT_OP: '!'; 243 | POW_OP: '^'; 244 | TRANSPOSE_OP: '\''; 245 | 246 | SAMPLE: '~'; 247 | EQ: '='; 248 | PLUS_EQ: '+='; 249 | MINUS_EQ: '-='; 250 | MULT_EQ: '*='; 251 | DIV_EQ: '/='; 252 | DOT_MULT_EQ: '.*='; 253 | DOT_DIV_EQ: './='; 254 | 255 | 256 | /* Types (section 3.1) */ 257 | 258 | primitiveType 259 | : REAL 260 | | INT 261 | ; 262 | 263 | vectorType 264 | : VECTOR 265 | | SIMPLEX 266 | | UNIT_VECTOR 267 | | ORDERED 268 | | POSITIVE_ORDERED 269 | | ROW_VECTOR 270 | ; 271 | 272 | matrixType 273 | : MATRIX 274 | | CORR_MATRIX 275 | | COV_MATRIX 276 | | CHOLESKY_FACTOR_COV 277 | | CHOLESKY_FACTOR_CORR 278 | ; 279 | 280 | type_ 281 | : primitiveType typeConstraints? arrayDim? 282 | | vectorType typeConstraints? arrayDim? 283 | | matrixType typeConstraints? arrayDim? 284 | ; 285 | 286 | typeConstraints 287 | : '<' typeConstraintList '>' 288 | ; 289 | 290 | typeConstraintList 291 | : typeConstraint (',' typeConstraint)* 292 | ; 293 | 294 | typeConstraint 295 | : IDENTIFIER '=' constraintExpression 296 | ; 297 | 298 | variableDecl 299 | : type_ IDENTIFIER arrayDim? ';' 300 | | type_ IDENTIFIER arrayDim? '=' expression ';' 301 | ; 302 | 303 | arrayDim 304 | : '[' expressionCommaListOpt ']' 305 | | '[' commaListOpt ']' 306 | ; 307 | 308 | commaListOpt 309 | : ','* 310 | ; 311 | 312 | variableDeclsOpt 313 | : variableDecl* 314 | ; 315 | 316 | /** Numeric Litterals (section 4.1) */ 317 | constant 318 | : IntegerLiteral 319 | | RealLiteral 320 | ; 321 | 322 | /** Variable (section 4.2) */ 323 | variable 324 | : IDENTIFIER 325 | ; 326 | 327 | /** Vector, matrix and array expressions (section 4.2) */ 328 | 329 | vectorExpr 330 | : '[' expressionCommaList ']' 331 | ; 332 | 333 | arrayExpr 334 | : '{' expressionCommaList '}' 335 | ; 336 | 337 | atom 338 | : constant 339 | | variable 340 | | vectorExpr 341 | | arrayExpr 342 | | arrayAccess=atom '[' indexExpressionCommaListOpt ']' 343 | | callExpr 344 | | paren='(' expression ')' 345 | ; 346 | 347 | callExpr 348 | : f=IDENTIFIER '(' expressionOrStringCommaList ')' truncation? 349 | | id1=IDENTIFIER '(' expression '|' expressionCommaList ')' 350 | ; 351 | 352 | expression 353 | : atom 354 | | e=expression TRANSPOSE_OP 355 | | e1=expression POW_OP e2=expression 356 | | op=(NOT_OP|PLUS_OP|MINUS_OP) e=expression 357 | | e1=expression op=(DOT_MULT_OP|DOT_DIV_OP) e2=expression 358 | | e1=expression LEFT_DIV_OP e2=expression 359 | | e1=expression op=(MULT_OP|DIV_OP|MOD_OP) e2=expression 360 | | e1=expression op=(PLUS_OP|MINUS_OP) e2=expression 361 | | e1=expression op=(LT_OP|LE_OP|GT_OP|GE_OP) e2=expression 362 | | e1=expression op=(EQ_OP|NEQ_OP) e2=expression 363 | | e1=expression AND_OP e2=expression 364 | | e1=expression OR_OP e2=expression 365 | | e1=expression '?' e2=expression ':' e3=expression 366 | ; 367 | 368 | constraintExpression 369 | : atom 370 | | e=constraintExpression TRANSPOSE_OP 371 | | e1=constraintExpression POW_OP e2=constraintExpression 372 | | op=(NOT_OP|PLUS_OP|MINUS_OP) e=constraintExpression 373 | | e1=constraintExpression op=(DOT_MULT_OP|DOT_DIV_OP) e2=constraintExpression 374 | | e1=constraintExpression LEFT_DIV_OP e2=constraintExpression 375 | | e1=constraintExpression op=(MULT_OP|DIV_OP|MOD_OP) e2=constraintExpression 376 | | e1=constraintExpression op=(PLUS_OP|MINUS_OP) e2=constraintExpression 377 | | e1=constraintExpression op=(LT_OP|LE_OP) e2=constraintExpression 378 | | e1=constraintExpression op=(EQ_OP|NEQ_OP) e2=constraintExpression 379 | | e1=constraintExpression AND_OP e2=constraintExpression 380 | | e1=constraintExpression OR_OP e2=constraintExpression 381 | | e1=constraintExpression '?' e2=constraintExpression ':' e3=constraintExpression 382 | ; 383 | 384 | indexExpression 385 | : /* empty */ 386 | | e=expression 387 | | e1=expression? sliceOp=':' e2=expression? 388 | ; 389 | 390 | expressionCommaList 391 | : expression (',' expression)* 392 | ; 393 | 394 | expressionCommaListOpt 395 | : expressionCommaList? 396 | ; 397 | 398 | indexExpressionCommaListOpt 399 | : indexExpression (',' indexExpression)* 400 | ; 401 | 402 | 403 | /** Statements (section 5) */ 404 | 405 | /** Assignment (section 5.1) */ 406 | 407 | lvalue 408 | : IDENTIFIER 409 | | IDENTIFIER '[' indexExpressionCommaListOpt ']' 410 | ; 411 | 412 | assignStmt 413 | : le=expression sample='~' re=expression ';' 414 | | lvalue eq=('='|'<-') e=expression ';' 415 | | lvalue op=(PLUS_EQ|MINUS_EQ|MULT_EQ|DIV_EQ|DOT_MULT_EQ|DOT_DIV_EQ) e=expression ';' 416 | ; 417 | 418 | /** Sampling (section 5.3) */ 419 | 420 | truncation 421 | // : 'T' '[' e1=expression? ',' e2=expression? ']' 422 | : IDENTIFIER '[' e1=expression? ',' e2=expression? ']' 423 | ; 424 | 425 | /** For loops (section 5.4) */ 426 | 427 | forStmt 428 | : FOR '(' IDENTIFIER IN atom ':' expression ')' statement 429 | | FOR '(' IDENTIFIER IN atom ')' statement 430 | ; 431 | 432 | 433 | /** Conditional statements (section 5.5) */ 434 | 435 | conditionalStmt 436 | : IF '(' expression ')' s1=statement (ELSE s2=statement)? 437 | ; 438 | 439 | 440 | /** While loops (section 5.6) */ 441 | 442 | whileStmt 443 | : WHILE '(' expression ')' statement 444 | ; 445 | 446 | 447 | /** Blocks (section 5.7) */ 448 | blockStmt 449 | : '{' variableDeclsOpt statementsOpt '}' 450 | ; 451 | 452 | 453 | /** Functions calls (sections 5.9 and 5.10) */ 454 | 455 | callStmt 456 | : callExpr ';' 457 | ; 458 | 459 | expressionOrString 460 | : expression 461 | | StringLiteral 462 | ; 463 | 464 | expressionOrStringCommaList: 465 | | expressionOrString (',' expressionOrString)* 466 | ; 467 | 468 | /** statements */ 469 | 470 | statement 471 | : assignStmt 472 | | forStmt 473 | | conditionalStmt 474 | | whileStmt 475 | | blockStmt 476 | | callStmt 477 | | BREAK ';' 478 | | CONTINUE ';' 479 | | returnStmt 480 | | empty=';' 481 | ; 482 | 483 | statementsOpt 484 | : statement* 485 | ; 486 | 487 | 488 | /** Functions (section 7) */ 489 | 490 | functionDecl 491 | : unsizedReturnType IDENTIFIER '(' parameterCommaListOpt ')' statement 492 | ; 493 | 494 | unsizedReturnType 495 | : VOID 496 | | unsizedType 497 | ; 498 | 499 | unsizedType 500 | : basicType unsizedDims? 501 | ; 502 | 503 | basicType 504 | : INT 505 | | REAL 506 | | VECTOR 507 | | ROW_VECTOR 508 | | MATRIX 509 | ; 510 | 511 | unsizedDims 512 | : '[' (commas+=',')* ']' 513 | ; 514 | 515 | parameterDecl 516 | : unsizedType IDENTIFIER 517 | ; 518 | 519 | parameterCommaList 520 | : parameterDecl (',' parameterDecl)* 521 | ; 522 | 523 | parameterCommaListOpt 524 | : parameterCommaList? 525 | ; 526 | 527 | returnStmt 528 | : RETURN expression? ';' 529 | ; 530 | 531 | functionDeclsOpt 532 | : functionDecl* 533 | ; 534 | 535 | /** Program blocks (section 6) */ 536 | 537 | functionBlock 538 | : FUNCTIONS '{' functionDeclsOpt '}' 539 | ; 540 | 541 | dataBlock 542 | : DATA '{' variableDeclsOpt '}' 543 | ; 544 | 545 | transformedDataBlock 546 | : TRANSFORMED DATA '{' variableDeclsOpt statementsOpt '}' 547 | ; 548 | 549 | parametersBlock 550 | : PARAMETERS '{' variableDeclsOpt '}' 551 | ; 552 | 553 | transformedParametersBlock 554 | : TRANSFORMED PARAMETERS '{' variableDeclsOpt statementsOpt '}' 555 | ; 556 | 557 | modelBlock 558 | : MODEL '{' variableDeclsOpt statementsOpt '}' 559 | | MODEL statement 560 | ; 561 | 562 | generatedQuantitiesBlock 563 | : GENERATED QUANTITIES '{' variableDeclsOpt statementsOpt '}' 564 | ; 565 | 566 | program 567 | : include? 568 | functionBlock? 569 | dataBlock? 570 | transformedDataBlock? 571 | parametersBlock? 572 | transformedParametersBlock? 573 | modelBlock? 574 | generatedQuantitiesBlock? 575 | EOF 576 | ; 577 | -------------------------------------------------------------------------------- /yaps/stanListener.py: -------------------------------------------------------------------------------- 1 | # Generated from yaps/stan.g4 by ANTLR 4.7.1 2 | from antlr4 import * 3 | if __name__ is not None and "." in __name__: 4 | from .stanParser import stanParser 5 | else: 6 | from stanParser import stanParser 7 | 8 | # This class defines a complete listener for a parse tree produced by stanParser. 9 | class stanListener(ParseTreeListener): 10 | 11 | # Enter a parse tree produced by stanParser#include. 12 | def enterInclude(self, ctx:stanParser.IncludeContext): 13 | pass 14 | 15 | # Exit a parse tree produced by stanParser#include. 16 | def exitInclude(self, ctx:stanParser.IncludeContext): 17 | pass 18 | 19 | 20 | # Enter a parse tree produced by stanParser#primitiveType. 21 | def enterPrimitiveType(self, ctx:stanParser.PrimitiveTypeContext): 22 | pass 23 | 24 | # Exit a parse tree produced by stanParser#primitiveType. 25 | def exitPrimitiveType(self, ctx:stanParser.PrimitiveTypeContext): 26 | pass 27 | 28 | 29 | # Enter a parse tree produced by stanParser#vectorType. 30 | def enterVectorType(self, ctx:stanParser.VectorTypeContext): 31 | pass 32 | 33 | # Exit a parse tree produced by stanParser#vectorType. 34 | def exitVectorType(self, ctx:stanParser.VectorTypeContext): 35 | pass 36 | 37 | 38 | # Enter a parse tree produced by stanParser#matrixType. 39 | def enterMatrixType(self, ctx:stanParser.MatrixTypeContext): 40 | pass 41 | 42 | # Exit a parse tree produced by stanParser#matrixType. 43 | def exitMatrixType(self, ctx:stanParser.MatrixTypeContext): 44 | pass 45 | 46 | 47 | # Enter a parse tree produced by stanParser#type_. 48 | def enterType_(self, ctx:stanParser.Type_Context): 49 | pass 50 | 51 | # Exit a parse tree produced by stanParser#type_. 52 | def exitType_(self, ctx:stanParser.Type_Context): 53 | pass 54 | 55 | 56 | # Enter a parse tree produced by stanParser#typeConstraints. 57 | def enterTypeConstraints(self, ctx:stanParser.TypeConstraintsContext): 58 | pass 59 | 60 | # Exit a parse tree produced by stanParser#typeConstraints. 61 | def exitTypeConstraints(self, ctx:stanParser.TypeConstraintsContext): 62 | pass 63 | 64 | 65 | # Enter a parse tree produced by stanParser#typeConstraintList. 66 | def enterTypeConstraintList(self, ctx:stanParser.TypeConstraintListContext): 67 | pass 68 | 69 | # Exit a parse tree produced by stanParser#typeConstraintList. 70 | def exitTypeConstraintList(self, ctx:stanParser.TypeConstraintListContext): 71 | pass 72 | 73 | 74 | # Enter a parse tree produced by stanParser#typeConstraint. 75 | def enterTypeConstraint(self, ctx:stanParser.TypeConstraintContext): 76 | pass 77 | 78 | # Exit a parse tree produced by stanParser#typeConstraint. 79 | def exitTypeConstraint(self, ctx:stanParser.TypeConstraintContext): 80 | pass 81 | 82 | 83 | # Enter a parse tree produced by stanParser#variableDecl. 84 | def enterVariableDecl(self, ctx:stanParser.VariableDeclContext): 85 | pass 86 | 87 | # Exit a parse tree produced by stanParser#variableDecl. 88 | def exitVariableDecl(self, ctx:stanParser.VariableDeclContext): 89 | pass 90 | 91 | 92 | # Enter a parse tree produced by stanParser#arrayDim. 93 | def enterArrayDim(self, ctx:stanParser.ArrayDimContext): 94 | pass 95 | 96 | # Exit a parse tree produced by stanParser#arrayDim. 97 | def exitArrayDim(self, ctx:stanParser.ArrayDimContext): 98 | pass 99 | 100 | 101 | # Enter a parse tree produced by stanParser#commaListOpt. 102 | def enterCommaListOpt(self, ctx:stanParser.CommaListOptContext): 103 | pass 104 | 105 | # Exit a parse tree produced by stanParser#commaListOpt. 106 | def exitCommaListOpt(self, ctx:stanParser.CommaListOptContext): 107 | pass 108 | 109 | 110 | # Enter a parse tree produced by stanParser#variableDeclsOpt. 111 | def enterVariableDeclsOpt(self, ctx:stanParser.VariableDeclsOptContext): 112 | pass 113 | 114 | # Exit a parse tree produced by stanParser#variableDeclsOpt. 115 | def exitVariableDeclsOpt(self, ctx:stanParser.VariableDeclsOptContext): 116 | pass 117 | 118 | 119 | # Enter a parse tree produced by stanParser#constant. 120 | def enterConstant(self, ctx:stanParser.ConstantContext): 121 | pass 122 | 123 | # Exit a parse tree produced by stanParser#constant. 124 | def exitConstant(self, ctx:stanParser.ConstantContext): 125 | pass 126 | 127 | 128 | # Enter a parse tree produced by stanParser#variable. 129 | def enterVariable(self, ctx:stanParser.VariableContext): 130 | pass 131 | 132 | # Exit a parse tree produced by stanParser#variable. 133 | def exitVariable(self, ctx:stanParser.VariableContext): 134 | pass 135 | 136 | 137 | # Enter a parse tree produced by stanParser#vectorExpr. 138 | def enterVectorExpr(self, ctx:stanParser.VectorExprContext): 139 | pass 140 | 141 | # Exit a parse tree produced by stanParser#vectorExpr. 142 | def exitVectorExpr(self, ctx:stanParser.VectorExprContext): 143 | pass 144 | 145 | 146 | # Enter a parse tree produced by stanParser#arrayExpr. 147 | def enterArrayExpr(self, ctx:stanParser.ArrayExprContext): 148 | pass 149 | 150 | # Exit a parse tree produced by stanParser#arrayExpr. 151 | def exitArrayExpr(self, ctx:stanParser.ArrayExprContext): 152 | pass 153 | 154 | 155 | # Enter a parse tree produced by stanParser#atom. 156 | def enterAtom(self, ctx:stanParser.AtomContext): 157 | pass 158 | 159 | # Exit a parse tree produced by stanParser#atom. 160 | def exitAtom(self, ctx:stanParser.AtomContext): 161 | pass 162 | 163 | 164 | # Enter a parse tree produced by stanParser#callExpr. 165 | def enterCallExpr(self, ctx:stanParser.CallExprContext): 166 | pass 167 | 168 | # Exit a parse tree produced by stanParser#callExpr. 169 | def exitCallExpr(self, ctx:stanParser.CallExprContext): 170 | pass 171 | 172 | 173 | # Enter a parse tree produced by stanParser#expression. 174 | def enterExpression(self, ctx:stanParser.ExpressionContext): 175 | pass 176 | 177 | # Exit a parse tree produced by stanParser#expression. 178 | def exitExpression(self, ctx:stanParser.ExpressionContext): 179 | pass 180 | 181 | 182 | # Enter a parse tree produced by stanParser#constraintExpression. 183 | def enterConstraintExpression(self, ctx:stanParser.ConstraintExpressionContext): 184 | pass 185 | 186 | # Exit a parse tree produced by stanParser#constraintExpression. 187 | def exitConstraintExpression(self, ctx:stanParser.ConstraintExpressionContext): 188 | pass 189 | 190 | 191 | # Enter a parse tree produced by stanParser#indexExpression. 192 | def enterIndexExpression(self, ctx:stanParser.IndexExpressionContext): 193 | pass 194 | 195 | # Exit a parse tree produced by stanParser#indexExpression. 196 | def exitIndexExpression(self, ctx:stanParser.IndexExpressionContext): 197 | pass 198 | 199 | 200 | # Enter a parse tree produced by stanParser#expressionCommaList. 201 | def enterExpressionCommaList(self, ctx:stanParser.ExpressionCommaListContext): 202 | pass 203 | 204 | # Exit a parse tree produced by stanParser#expressionCommaList. 205 | def exitExpressionCommaList(self, ctx:stanParser.ExpressionCommaListContext): 206 | pass 207 | 208 | 209 | # Enter a parse tree produced by stanParser#expressionCommaListOpt. 210 | def enterExpressionCommaListOpt(self, ctx:stanParser.ExpressionCommaListOptContext): 211 | pass 212 | 213 | # Exit a parse tree produced by stanParser#expressionCommaListOpt. 214 | def exitExpressionCommaListOpt(self, ctx:stanParser.ExpressionCommaListOptContext): 215 | pass 216 | 217 | 218 | # Enter a parse tree produced by stanParser#indexExpressionCommaListOpt. 219 | def enterIndexExpressionCommaListOpt(self, ctx:stanParser.IndexExpressionCommaListOptContext): 220 | pass 221 | 222 | # Exit a parse tree produced by stanParser#indexExpressionCommaListOpt. 223 | def exitIndexExpressionCommaListOpt(self, ctx:stanParser.IndexExpressionCommaListOptContext): 224 | pass 225 | 226 | 227 | # Enter a parse tree produced by stanParser#lvalue. 228 | def enterLvalue(self, ctx:stanParser.LvalueContext): 229 | pass 230 | 231 | # Exit a parse tree produced by stanParser#lvalue. 232 | def exitLvalue(self, ctx:stanParser.LvalueContext): 233 | pass 234 | 235 | 236 | # Enter a parse tree produced by stanParser#assignStmt. 237 | def enterAssignStmt(self, ctx:stanParser.AssignStmtContext): 238 | pass 239 | 240 | # Exit a parse tree produced by stanParser#assignStmt. 241 | def exitAssignStmt(self, ctx:stanParser.AssignStmtContext): 242 | pass 243 | 244 | 245 | # Enter a parse tree produced by stanParser#truncation. 246 | def enterTruncation(self, ctx:stanParser.TruncationContext): 247 | pass 248 | 249 | # Exit a parse tree produced by stanParser#truncation. 250 | def exitTruncation(self, ctx:stanParser.TruncationContext): 251 | pass 252 | 253 | 254 | # Enter a parse tree produced by stanParser#forStmt. 255 | def enterForStmt(self, ctx:stanParser.ForStmtContext): 256 | pass 257 | 258 | # Exit a parse tree produced by stanParser#forStmt. 259 | def exitForStmt(self, ctx:stanParser.ForStmtContext): 260 | pass 261 | 262 | 263 | # Enter a parse tree produced by stanParser#conditionalStmt. 264 | def enterConditionalStmt(self, ctx:stanParser.ConditionalStmtContext): 265 | pass 266 | 267 | # Exit a parse tree produced by stanParser#conditionalStmt. 268 | def exitConditionalStmt(self, ctx:stanParser.ConditionalStmtContext): 269 | pass 270 | 271 | 272 | # Enter a parse tree produced by stanParser#whileStmt. 273 | def enterWhileStmt(self, ctx:stanParser.WhileStmtContext): 274 | pass 275 | 276 | # Exit a parse tree produced by stanParser#whileStmt. 277 | def exitWhileStmt(self, ctx:stanParser.WhileStmtContext): 278 | pass 279 | 280 | 281 | # Enter a parse tree produced by stanParser#blockStmt. 282 | def enterBlockStmt(self, ctx:stanParser.BlockStmtContext): 283 | pass 284 | 285 | # Exit a parse tree produced by stanParser#blockStmt. 286 | def exitBlockStmt(self, ctx:stanParser.BlockStmtContext): 287 | pass 288 | 289 | 290 | # Enter a parse tree produced by stanParser#callStmt. 291 | def enterCallStmt(self, ctx:stanParser.CallStmtContext): 292 | pass 293 | 294 | # Exit a parse tree produced by stanParser#callStmt. 295 | def exitCallStmt(self, ctx:stanParser.CallStmtContext): 296 | pass 297 | 298 | 299 | # Enter a parse tree produced by stanParser#expressionOrString. 300 | def enterExpressionOrString(self, ctx:stanParser.ExpressionOrStringContext): 301 | pass 302 | 303 | # Exit a parse tree produced by stanParser#expressionOrString. 304 | def exitExpressionOrString(self, ctx:stanParser.ExpressionOrStringContext): 305 | pass 306 | 307 | 308 | # Enter a parse tree produced by stanParser#expressionOrStringCommaList. 309 | def enterExpressionOrStringCommaList(self, ctx:stanParser.ExpressionOrStringCommaListContext): 310 | pass 311 | 312 | # Exit a parse tree produced by stanParser#expressionOrStringCommaList. 313 | def exitExpressionOrStringCommaList(self, ctx:stanParser.ExpressionOrStringCommaListContext): 314 | pass 315 | 316 | 317 | # Enter a parse tree produced by stanParser#statement. 318 | def enterStatement(self, ctx:stanParser.StatementContext): 319 | pass 320 | 321 | # Exit a parse tree produced by stanParser#statement. 322 | def exitStatement(self, ctx:stanParser.StatementContext): 323 | pass 324 | 325 | 326 | # Enter a parse tree produced by stanParser#statementsOpt. 327 | def enterStatementsOpt(self, ctx:stanParser.StatementsOptContext): 328 | pass 329 | 330 | # Exit a parse tree produced by stanParser#statementsOpt. 331 | def exitStatementsOpt(self, ctx:stanParser.StatementsOptContext): 332 | pass 333 | 334 | 335 | # Enter a parse tree produced by stanParser#functionDecl. 336 | def enterFunctionDecl(self, ctx:stanParser.FunctionDeclContext): 337 | pass 338 | 339 | # Exit a parse tree produced by stanParser#functionDecl. 340 | def exitFunctionDecl(self, ctx:stanParser.FunctionDeclContext): 341 | pass 342 | 343 | 344 | # Enter a parse tree produced by stanParser#unsizedReturnType. 345 | def enterUnsizedReturnType(self, ctx:stanParser.UnsizedReturnTypeContext): 346 | pass 347 | 348 | # Exit a parse tree produced by stanParser#unsizedReturnType. 349 | def exitUnsizedReturnType(self, ctx:stanParser.UnsizedReturnTypeContext): 350 | pass 351 | 352 | 353 | # Enter a parse tree produced by stanParser#unsizedType. 354 | def enterUnsizedType(self, ctx:stanParser.UnsizedTypeContext): 355 | pass 356 | 357 | # Exit a parse tree produced by stanParser#unsizedType. 358 | def exitUnsizedType(self, ctx:stanParser.UnsizedTypeContext): 359 | pass 360 | 361 | 362 | # Enter a parse tree produced by stanParser#basicType. 363 | def enterBasicType(self, ctx:stanParser.BasicTypeContext): 364 | pass 365 | 366 | # Exit a parse tree produced by stanParser#basicType. 367 | def exitBasicType(self, ctx:stanParser.BasicTypeContext): 368 | pass 369 | 370 | 371 | # Enter a parse tree produced by stanParser#unsizedDims. 372 | def enterUnsizedDims(self, ctx:stanParser.UnsizedDimsContext): 373 | pass 374 | 375 | # Exit a parse tree produced by stanParser#unsizedDims. 376 | def exitUnsizedDims(self, ctx:stanParser.UnsizedDimsContext): 377 | pass 378 | 379 | 380 | # Enter a parse tree produced by stanParser#parameterDecl. 381 | def enterParameterDecl(self, ctx:stanParser.ParameterDeclContext): 382 | pass 383 | 384 | # Exit a parse tree produced by stanParser#parameterDecl. 385 | def exitParameterDecl(self, ctx:stanParser.ParameterDeclContext): 386 | pass 387 | 388 | 389 | # Enter a parse tree produced by stanParser#parameterCommaList. 390 | def enterParameterCommaList(self, ctx:stanParser.ParameterCommaListContext): 391 | pass 392 | 393 | # Exit a parse tree produced by stanParser#parameterCommaList. 394 | def exitParameterCommaList(self, ctx:stanParser.ParameterCommaListContext): 395 | pass 396 | 397 | 398 | # Enter a parse tree produced by stanParser#parameterCommaListOpt. 399 | def enterParameterCommaListOpt(self, ctx:stanParser.ParameterCommaListOptContext): 400 | pass 401 | 402 | # Exit a parse tree produced by stanParser#parameterCommaListOpt. 403 | def exitParameterCommaListOpt(self, ctx:stanParser.ParameterCommaListOptContext): 404 | pass 405 | 406 | 407 | # Enter a parse tree produced by stanParser#returnStmt. 408 | def enterReturnStmt(self, ctx:stanParser.ReturnStmtContext): 409 | pass 410 | 411 | # Exit a parse tree produced by stanParser#returnStmt. 412 | def exitReturnStmt(self, ctx:stanParser.ReturnStmtContext): 413 | pass 414 | 415 | 416 | # Enter a parse tree produced by stanParser#functionDeclsOpt. 417 | def enterFunctionDeclsOpt(self, ctx:stanParser.FunctionDeclsOptContext): 418 | pass 419 | 420 | # Exit a parse tree produced by stanParser#functionDeclsOpt. 421 | def exitFunctionDeclsOpt(self, ctx:stanParser.FunctionDeclsOptContext): 422 | pass 423 | 424 | 425 | # Enter a parse tree produced by stanParser#functionBlock. 426 | def enterFunctionBlock(self, ctx:stanParser.FunctionBlockContext): 427 | pass 428 | 429 | # Exit a parse tree produced by stanParser#functionBlock. 430 | def exitFunctionBlock(self, ctx:stanParser.FunctionBlockContext): 431 | pass 432 | 433 | 434 | # Enter a parse tree produced by stanParser#dataBlock. 435 | def enterDataBlock(self, ctx:stanParser.DataBlockContext): 436 | pass 437 | 438 | # Exit a parse tree produced by stanParser#dataBlock. 439 | def exitDataBlock(self, ctx:stanParser.DataBlockContext): 440 | pass 441 | 442 | 443 | # Enter a parse tree produced by stanParser#transformedDataBlock. 444 | def enterTransformedDataBlock(self, ctx:stanParser.TransformedDataBlockContext): 445 | pass 446 | 447 | # Exit a parse tree produced by stanParser#transformedDataBlock. 448 | def exitTransformedDataBlock(self, ctx:stanParser.TransformedDataBlockContext): 449 | pass 450 | 451 | 452 | # Enter a parse tree produced by stanParser#parametersBlock. 453 | def enterParametersBlock(self, ctx:stanParser.ParametersBlockContext): 454 | pass 455 | 456 | # Exit a parse tree produced by stanParser#parametersBlock. 457 | def exitParametersBlock(self, ctx:stanParser.ParametersBlockContext): 458 | pass 459 | 460 | 461 | # Enter a parse tree produced by stanParser#transformedParametersBlock. 462 | def enterTransformedParametersBlock(self, ctx:stanParser.TransformedParametersBlockContext): 463 | pass 464 | 465 | # Exit a parse tree produced by stanParser#transformedParametersBlock. 466 | def exitTransformedParametersBlock(self, ctx:stanParser.TransformedParametersBlockContext): 467 | pass 468 | 469 | 470 | # Enter a parse tree produced by stanParser#modelBlock. 471 | def enterModelBlock(self, ctx:stanParser.ModelBlockContext): 472 | pass 473 | 474 | # Exit a parse tree produced by stanParser#modelBlock. 475 | def exitModelBlock(self, ctx:stanParser.ModelBlockContext): 476 | pass 477 | 478 | 479 | # Enter a parse tree produced by stanParser#generatedQuantitiesBlock. 480 | def enterGeneratedQuantitiesBlock(self, ctx:stanParser.GeneratedQuantitiesBlockContext): 481 | pass 482 | 483 | # Exit a parse tree produced by stanParser#generatedQuantitiesBlock. 484 | def exitGeneratedQuantitiesBlock(self, ctx:stanParser.GeneratedQuantitiesBlockContext): 485 | pass 486 | 487 | 488 | # Enter a parse tree produced by stanParser#program. 489 | def enterProgram(self, ctx:stanParser.ProgramContext): 490 | pass 491 | 492 | # Exit a parse tree produced by stanParser#program. 493 | def exitProgram(self, ctx:stanParser.ProgramContext): 494 | pass 495 | 496 | 497 | --------------------------------------------------------------------------------