cmdstanpy 1.2.0__tar.gz → 1.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cmdstanpy-1.2.0/cmdstanpy.egg-info → cmdstanpy-1.2.1}/PKG-INFO +1 -1
- cmdstanpy-1.2.1/cmdstanpy/_version.py +3 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/cmdstan_args.py +15 -6
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/model.py +47 -14
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/stanfit/gq.py +6 -6
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/stanfit/mcmc.py +9 -3
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/stanfit/pathfinder.py +12 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/utils/stancsv.py +8 -2
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1/cmdstanpy.egg-info}/PKG-INFO +1 -1
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_cmdstan_args.py +1 -1
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_generate_quantities.py +7 -5
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_log_prob.py +15 -7
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_pathfinder.py +30 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_sample.py +27 -12
- cmdstanpy-1.2.0/cmdstanpy/_version.py +0 -3
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/LICENSE.md +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/MANIFEST.in +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/README.md +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/__init__.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/compilation.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/install_cmdstan.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/install_cxx_toolchain.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/progress.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/py.typed +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/stanfit/__init__.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/stanfit/laplace.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/stanfit/metadata.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/stanfit/mle.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/stanfit/runset.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/stanfit/vb.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/utils/__init__.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/utils/cmdstan.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/utils/command.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/utils/data_munging.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/utils/filesystem.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/utils/json.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy/utils/logging.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy.egg-info/SOURCES.txt +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy.egg-info/dependency_links.txt +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy.egg-info/entry_points.txt +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy.egg-info/requires.txt +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/cmdstanpy.egg-info/top_level.txt +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/pyproject.toml +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/requirements-optional.txt +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/requirements-test.txt +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/requirements.txt +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/setup.cfg +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/setup.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_compiler_opts.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_compliance.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_cxx_installation.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_install_cmdstan.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_laplace.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_metadata.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_model.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_optimize.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_runset.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_utils.py +0 -0
- {cmdstanpy-1.2.0 → cmdstanpy-1.2.1}/test/test_variational.py +0 -0
|
@@ -7,7 +7,7 @@ from time import time
|
|
|
7
7
|
from typing import Any, Dict, List, Mapping, Optional, Union
|
|
8
8
|
|
|
9
9
|
import numpy as np
|
|
10
|
-
from numpy.random import
|
|
10
|
+
from numpy.random import default_rng
|
|
11
11
|
|
|
12
12
|
from cmdstanpy import _TMPDIR
|
|
13
13
|
from cmdstanpy.utils import (
|
|
@@ -139,10 +139,9 @@ class SamplerArgs:
|
|
|
139
139
|
'Value for iter_warmup must be a non-negative integer,'
|
|
140
140
|
' found {}.'.format(self.iter_warmup)
|
|
141
141
|
)
|
|
142
|
-
if self.iter_warmup
|
|
142
|
+
if self.iter_warmup == 0 and self.adapt_engaged:
|
|
143
143
|
raise ValueError(
|
|
144
|
-
'
|
|
145
|
-
'cannot specify warmup iterations.'
|
|
144
|
+
'Must specify iter_warmup > 0 when adapt_engaged=True.'
|
|
146
145
|
)
|
|
147
146
|
if self.iter_sampling is not None:
|
|
148
147
|
if self.iter_sampling < 0 or not isinstance(
|
|
@@ -541,6 +540,8 @@ class PathfinderArgs:
|
|
|
541
540
|
num_draws: Optional[int] = None,
|
|
542
541
|
num_elbo_draws: Optional[int] = None,
|
|
543
542
|
save_single_paths: bool = False,
|
|
543
|
+
psis_resample: bool = True,
|
|
544
|
+
calculate_lp: bool = True,
|
|
544
545
|
) -> None:
|
|
545
546
|
self.init_alpha = init_alpha
|
|
546
547
|
self.tol_obj = tol_obj
|
|
@@ -557,6 +558,8 @@ class PathfinderArgs:
|
|
|
557
558
|
self.num_elbo_draws = num_elbo_draws
|
|
558
559
|
|
|
559
560
|
self.save_single_paths = save_single_paths
|
|
561
|
+
self.psis_resample = psis_resample
|
|
562
|
+
self.calculate_lp = calculate_lp
|
|
560
563
|
|
|
561
564
|
def validate(self, _chains: Optional[int] = None) -> None:
|
|
562
565
|
"""
|
|
@@ -609,6 +612,12 @@ class PathfinderArgs:
|
|
|
609
612
|
if self.save_single_paths:
|
|
610
613
|
cmd.append('save_single_paths=1')
|
|
611
614
|
|
|
615
|
+
if not self.psis_resample:
|
|
616
|
+
cmd.append('psis_resample=0')
|
|
617
|
+
|
|
618
|
+
if not self.calculate_lp:
|
|
619
|
+
cmd.append('calculate_lp=0')
|
|
620
|
+
|
|
612
621
|
return cmd
|
|
613
622
|
|
|
614
623
|
|
|
@@ -868,8 +877,8 @@ class CmdStanArgs:
|
|
|
868
877
|
)
|
|
869
878
|
|
|
870
879
|
if self.seed is None:
|
|
871
|
-
rng =
|
|
872
|
-
self.seed = rng.
|
|
880
|
+
rng = default_rng()
|
|
881
|
+
self.seed = rng.integers(low=1, high=99999, size=1).item()
|
|
873
882
|
else:
|
|
874
883
|
if not isinstance(self.seed, (int, list, np.integer)):
|
|
875
884
|
raise ValueError(
|
|
@@ -80,12 +80,12 @@ class CmdStanModel:
|
|
|
80
80
|
"""
|
|
81
81
|
The constructor method allows model instantiation given either the
|
|
82
82
|
Stan program source file or the compiled executable, or both.
|
|
83
|
-
|
|
84
|
-
unless the argument ``compile=False`` is specified.
|
|
85
|
-
The set of constructor arguments are:
|
|
83
|
+
This will compile the model if provided a Stan file and no executable,
|
|
86
84
|
|
|
87
85
|
:param model_name: Model name, used for output file names.
|
|
88
86
|
Optional, default is the base filename of the Stan program file.
|
|
87
|
+
Deprecated: In version 2.0.0, model name cannot be
|
|
88
|
+
specified and will always be taken from executable.
|
|
89
89
|
|
|
90
90
|
:param stan_file: Path to Stan program file.
|
|
91
91
|
|
|
@@ -94,9 +94,8 @@ class CmdStanModel:
|
|
|
94
94
|
the compiled executable file are specified, the base filenames
|
|
95
95
|
must match, (but different directory locations are allowed).
|
|
96
96
|
|
|
97
|
-
:param
|
|
98
|
-
|
|
99
|
-
an existing executable is found.
|
|
97
|
+
:param force_compile: If ``True``, always compile, even if there
|
|
98
|
+
is an existing executable file for this model.
|
|
100
99
|
|
|
101
100
|
:param stanc_options: Options for stanc compiler, specified as a Python
|
|
102
101
|
dictionary containing Stanc3 compiler option name, value pairs.
|
|
@@ -109,6 +108,13 @@ class CmdStanModel:
|
|
|
109
108
|
:param user_header: A path to a header file to include during C++
|
|
110
109
|
compilation.
|
|
111
110
|
Optional.
|
|
111
|
+
|
|
112
|
+
:param compile: Whether or not to compile the model. Default is ``True``.
|
|
113
|
+
If set to the string ``"force"``, it will always compile even if
|
|
114
|
+
an existing executable is found.
|
|
115
|
+
Deprecated: Use ``force_compile`` instead. The ability to instantiate
|
|
116
|
+
a CmdStanModel without an executable will be removed in version 2.0.0.
|
|
117
|
+
|
|
112
118
|
"""
|
|
113
119
|
|
|
114
120
|
def __init__(
|
|
@@ -126,14 +132,16 @@ class CmdStanModel:
|
|
|
126
132
|
"""
|
|
127
133
|
Initialize object given constructor args.
|
|
128
134
|
|
|
129
|
-
:param model_name: Model name, used for output file names.
|
|
135
|
+
:param model_name: Deprecated. Model name, used for output file names.
|
|
130
136
|
:param stan_file: Path to Stan program file.
|
|
131
137
|
:param exe_file: Path to compiled executable file.
|
|
132
|
-
:param
|
|
138
|
+
:param force_compile: Whether or not to force recompilation if
|
|
139
|
+
executable file already exists.
|
|
133
140
|
:param stanc_options: Options for stanc compiler.
|
|
134
141
|
:param cpp_options: Options for C++ compiler.
|
|
135
142
|
:param user_header: A path to a header file to include during C++
|
|
136
143
|
compilation.
|
|
144
|
+
:param compile: Deprecated. Whether or not to compile the model.
|
|
137
145
|
"""
|
|
138
146
|
self._name = ''
|
|
139
147
|
self._stan_file = None
|
|
@@ -446,6 +454,9 @@ class CmdStanModel:
|
|
|
446
454
|
_internal: bool = False,
|
|
447
455
|
) -> None:
|
|
448
456
|
"""
|
|
457
|
+
Deprecated: To compile a model, use the :class:`~cmdstanpy.CmdStanModel`
|
|
458
|
+
constructor or :func:`cmdstanpy.compile_stan_file()`.
|
|
459
|
+
|
|
449
460
|
Compile the given Stan program file. Translates the Stan code to
|
|
450
461
|
C++, then calls the C++ compiler.
|
|
451
462
|
|
|
@@ -562,7 +573,7 @@ class CmdStanModel:
|
|
|
562
573
|
|
|
563
574
|
:param seed: The seed for random number generator. Must be an integer
|
|
564
575
|
between 0 and 2^32 - 1. If unspecified,
|
|
565
|
-
:
|
|
576
|
+
:func:`numpy.random.default_rng` is used to generate a seed.
|
|
566
577
|
|
|
567
578
|
:param inits: Specifies how the sampler initializes parameter values.
|
|
568
579
|
Initialization is either uniform random on a range centered on 0,
|
|
@@ -789,7 +800,7 @@ class CmdStanModel:
|
|
|
789
800
|
|
|
790
801
|
:param seed: The seed for random number generator. Must be an integer
|
|
791
802
|
between 0 and 2^32 - 1. If unspecified,
|
|
792
|
-
:
|
|
803
|
+
:func:`numpy.random.default_rng`
|
|
793
804
|
is used to generate a seed which will be used for all chains.
|
|
794
805
|
When the same seed is used across all chains,
|
|
795
806
|
the chain-id is used to advance the RNG to avoid dependent samples.
|
|
@@ -1231,7 +1242,7 @@ class CmdStanModel:
|
|
|
1231
1242
|
|
|
1232
1243
|
:param seed: The seed for random number generator. Must be an integer
|
|
1233
1244
|
between 0 and 2^32 - 1. If unspecified,
|
|
1234
|
-
:
|
|
1245
|
+
:func:`numpy.random.default_rng`
|
|
1235
1246
|
is used to generate a seed which will be used for all chains.
|
|
1236
1247
|
*NOTE: Specifying the seed will guarantee the same result for
|
|
1237
1248
|
multiple invocations of this method with the same inputs. However
|
|
@@ -1432,7 +1443,7 @@ class CmdStanModel:
|
|
|
1432
1443
|
|
|
1433
1444
|
:param seed: The seed for random number generator. Must be an integer
|
|
1434
1445
|
between 0 and 2^32 - 1. If unspecified,
|
|
1435
|
-
:
|
|
1446
|
+
:func:`numpy.random.default_rng`
|
|
1436
1447
|
is used to generate a seed which will be used for all chains.
|
|
1437
1448
|
|
|
1438
1449
|
:param inits: Specifies how the sampler initializes parameter values.
|
|
@@ -1612,6 +1623,8 @@ class CmdStanModel:
|
|
|
1612
1623
|
draws: Optional[int] = None,
|
|
1613
1624
|
num_single_draws: Optional[int] = None,
|
|
1614
1625
|
num_elbo_draws: Optional[int] = None,
|
|
1626
|
+
psis_resample: bool = True,
|
|
1627
|
+
calculate_lp: bool = True,
|
|
1615
1628
|
# arguments standard to all methods
|
|
1616
1629
|
seed: Optional[int] = None,
|
|
1617
1630
|
inits: Union[Dict[str, float], float, str, os.PathLike, None] = None,
|
|
@@ -1645,9 +1658,17 @@ class CmdStanModel:
|
|
|
1645
1658
|
|
|
1646
1659
|
:param num_elbo_draws: Number of Monte Carlo draws to evaluate ELBO.
|
|
1647
1660
|
|
|
1661
|
+
:param psis_resample: Whether or not to use Pareto Smoothed Importance
|
|
1662
|
+
Sampling on the result of the individual Pathfinders. If False, the
|
|
1663
|
+
result contains the draws from each path.
|
|
1664
|
+
|
|
1665
|
+
:param calculate_lp: Whether or not to calculate the log probability
|
|
1666
|
+
for approximate draws. If False, this also implies that
|
|
1667
|
+
``psis_resample`` will be set to False.
|
|
1668
|
+
|
|
1648
1669
|
:param seed: The seed for random number generator. Must be an integer
|
|
1649
1670
|
between 0 and 2^32 - 1. If unspecified,
|
|
1650
|
-
:
|
|
1671
|
+
:func:`numpy.random.default_rng` is used to generate a seed.
|
|
1651
1672
|
|
|
1652
1673
|
:param inits: Specifies how the algorithm initializes parameter values.
|
|
1653
1674
|
Initialization is either uniform random on a range centered on 0,
|
|
@@ -1726,12 +1747,22 @@ class CmdStanModel:
|
|
|
1726
1747
|
Research, 23(306), 1–49. Retrieved from
|
|
1727
1748
|
http://jmlr.org/papers/v23/21-0889.html
|
|
1728
1749
|
"""
|
|
1729
|
-
|
|
1750
|
+
|
|
1751
|
+
exe_info = self.exe_info()
|
|
1752
|
+
if cmdstan_version_before(2, 33, exe_info):
|
|
1730
1753
|
raise ValueError(
|
|
1731
1754
|
"Method 'pathfinder' not available for CmdStan versions "
|
|
1732
1755
|
"before 2.33"
|
|
1733
1756
|
)
|
|
1734
1757
|
|
|
1758
|
+
if (not psis_resample or not calculate_lp) and cmdstan_version_before(
|
|
1759
|
+
2, 34, exe_info
|
|
1760
|
+
):
|
|
1761
|
+
raise ValueError(
|
|
1762
|
+
"Arguments 'psis_resample' and 'calculate_lp' are only "
|
|
1763
|
+
"available for CmdStan versions 2.34 and later"
|
|
1764
|
+
)
|
|
1765
|
+
|
|
1735
1766
|
if num_paths == 1:
|
|
1736
1767
|
if num_single_draws is None:
|
|
1737
1768
|
num_single_draws = draws
|
|
@@ -1754,6 +1785,8 @@ class CmdStanModel:
|
|
|
1754
1785
|
max_lbfgs_iters=max_lbfgs_iters,
|
|
1755
1786
|
num_draws=num_single_draws,
|
|
1756
1787
|
num_elbo_draws=num_elbo_draws,
|
|
1788
|
+
psis_resample=psis_resample,
|
|
1789
|
+
calculate_lp=calculate_lp,
|
|
1757
1790
|
)
|
|
1758
1791
|
|
|
1759
1792
|
with temp_single_json(data) as _data, temp_inits(inits) as _inits:
|
|
@@ -323,6 +323,8 @@ class CmdStanGQ(Generic[Fit]):
|
|
|
323
323
|
|
|
324
324
|
self._assemble_generated_quantities()
|
|
325
325
|
|
|
326
|
+
all_columns = ['chain__', 'iter__', 'draw__'] + list(self.column_names)
|
|
327
|
+
|
|
326
328
|
gq_cols: List[str] = []
|
|
327
329
|
mcmc_vars: List[str] = []
|
|
328
330
|
if vars is not None:
|
|
@@ -341,10 +343,12 @@ class CmdStanGQ(Generic[Fit]):
|
|
|
341
343
|
info.start_idx : info.end_idx
|
|
342
344
|
]
|
|
343
345
|
)
|
|
346
|
+
elif var in ['chain__', 'iter__', 'draw__']:
|
|
347
|
+
gq_cols.append(var)
|
|
344
348
|
else:
|
|
345
349
|
raise ValueError('Unknown variable: {}'.format(var))
|
|
346
350
|
else:
|
|
347
|
-
gq_cols =
|
|
351
|
+
gq_cols = all_columns
|
|
348
352
|
vars_list = gq_cols
|
|
349
353
|
|
|
350
354
|
previous_draws_pd = self._previous_draws_pd(mcmc_vars, inc_warmup)
|
|
@@ -369,13 +373,9 @@ class CmdStanGQ(Generic[Fit]):
|
|
|
369
373
|
)
|
|
370
374
|
draws = np.concatenate([chains_col, iter_col, draw_col, draws], axis=2)
|
|
371
375
|
|
|
372
|
-
vars_list = ['chain__', 'iter__', 'draw__'] + vars_list
|
|
373
|
-
if gq_cols:
|
|
374
|
-
gq_cols = ['chain__', 'iter__', 'draw__'] + gq_cols
|
|
375
|
-
|
|
376
376
|
draws_pd = pd.DataFrame(
|
|
377
377
|
data=flatten_chains(draws),
|
|
378
|
-
columns=
|
|
378
|
+
columns=all_columns,
|
|
379
379
|
)
|
|
380
380
|
|
|
381
381
|
if inc_sample and mcmc_vars:
|
|
@@ -441,6 +441,12 @@ class CmdStanMCMC:
|
|
|
441
441
|
self._metric[chain, i, :] = [
|
|
442
442
|
float(x) for x in xs
|
|
443
443
|
]
|
|
444
|
+
else: # unit_e changed in 2.34 to have an extra line
|
|
445
|
+
pos = fd.tell()
|
|
446
|
+
line = fd.readline().strip()
|
|
447
|
+
if not line.startswith('#'):
|
|
448
|
+
fd.seek(pos)
|
|
449
|
+
|
|
444
450
|
# process draws
|
|
445
451
|
for i in range(sampling_iter_start, num_draws):
|
|
446
452
|
line = fd.readline().strip()
|
|
@@ -609,10 +615,12 @@ class CmdStanMCMC:
|
|
|
609
615
|
cols.extend(
|
|
610
616
|
self.column_names[info.start_idx : info.end_idx]
|
|
611
617
|
)
|
|
618
|
+
elif var in ['chain__', 'iter__', 'draw__']:
|
|
619
|
+
cols.append(var)
|
|
612
620
|
else:
|
|
613
621
|
raise ValueError(f'Unknown variable: {var}')
|
|
614
622
|
else:
|
|
615
|
-
cols = list(self.column_names)
|
|
623
|
+
cols = ['chain__', 'iter__', 'draw__'] + list(self.column_names)
|
|
616
624
|
|
|
617
625
|
draws = self.draws(inc_warmup=inc_warmup)
|
|
618
626
|
# add long-form columns for chain, iteration, draw
|
|
@@ -634,8 +642,6 @@ class CmdStanMCMC:
|
|
|
634
642
|
)
|
|
635
643
|
draws = np.concatenate([chains_col, iter_col, draw_col, draws], axis=2)
|
|
636
644
|
|
|
637
|
-
cols = ['chain__', 'iter__', 'draw__'] + cols
|
|
638
|
-
|
|
639
645
|
return pd.DataFrame(
|
|
640
646
|
data=flatten_chains(draws),
|
|
641
647
|
columns=['chain__', 'iter__', 'draw__'] + list(self.column_names),
|
|
@@ -206,6 +206,18 @@ class CmdStanPathfinder:
|
|
|
206
206
|
"""
|
|
207
207
|
return self._metadata.cmdstan_config['column_names'] # type: ignore
|
|
208
208
|
|
|
209
|
+
@property
|
|
210
|
+
def is_resampled(self) -> bool:
|
|
211
|
+
"""
|
|
212
|
+
Returns True if the draws were resampled from several Pathfinder
|
|
213
|
+
approximations, False otherwise.
|
|
214
|
+
"""
|
|
215
|
+
return ( # type: ignore
|
|
216
|
+
self._metadata.cmdstan_config.get("num_paths", 4) > 1
|
|
217
|
+
and self._metadata.cmdstan_config.get('psis_resample', 1) == 1
|
|
218
|
+
and self._metadata.cmdstan_config.get('calculate_lp', 1) == 1
|
|
219
|
+
)
|
|
220
|
+
|
|
209
221
|
def save_csvfiles(self, dir: Optional[str] = None) -> None:
|
|
210
222
|
"""
|
|
211
223
|
Move output CSV files to specified directory. If files were
|
|
@@ -289,10 +289,16 @@ def scan_hmc_params(
|
|
|
289
289
|
raise ValueError(
|
|
290
290
|
'line {}: invalid step size: {}'.format(lineno, step_size)
|
|
291
291
|
) from e
|
|
292
|
-
|
|
293
|
-
return lineno
|
|
292
|
+
before_metric = fd.tell()
|
|
294
293
|
line = fd.readline().strip()
|
|
295
294
|
lineno += 1
|
|
295
|
+
if metric == 'unit_e':
|
|
296
|
+
if line.startswith("# No free parameters"):
|
|
297
|
+
return lineno
|
|
298
|
+
else:
|
|
299
|
+
fd.seek(before_metric)
|
|
300
|
+
return lineno - 1
|
|
301
|
+
|
|
296
302
|
if not (
|
|
297
303
|
(
|
|
298
304
|
metric == 'diag_e'
|
|
@@ -111,7 +111,7 @@ def test_bad() -> None:
|
|
|
111
111
|
with pytest.raises(ValueError):
|
|
112
112
|
args.validate(chains=2)
|
|
113
113
|
|
|
114
|
-
args = SamplerArgs(iter_warmup=
|
|
114
|
+
args = SamplerArgs(iter_warmup=0, adapt_engaged=True)
|
|
115
115
|
with pytest.raises(ValueError):
|
|
116
116
|
args.validate(chains=2)
|
|
117
117
|
|
|
@@ -85,9 +85,11 @@ def test_from_csv_files(caplog: pytest.LogCaptureFixture) -> None:
|
|
|
85
85
|
- 3 # chain, iter, draw duplicates
|
|
86
86
|
)
|
|
87
87
|
|
|
88
|
-
assert list(bern_gqs.draws_pd(vars=['y_rep']).columns) == (
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
assert list(bern_gqs.draws_pd(vars=['y_rep']).columns) == (column_names)
|
|
89
|
+
|
|
90
|
+
assert list(
|
|
91
|
+
bern_gqs.draws_pd(vars=["chain__", "iter__", "draw__", 'y_rep']).columns
|
|
92
|
+
) == (["chain__", "iter__", "draw__"] + column_names)
|
|
91
93
|
|
|
92
94
|
|
|
93
95
|
def test_pd_xr_agreement():
|
|
@@ -315,9 +317,9 @@ def test_save_warmup(caplog: pytest.LogCaptureFixture) -> None:
|
|
|
315
317
|
assert bern_gqs.draws_pd(inc_warmup=True).shape == (800, 13)
|
|
316
318
|
assert bern_gqs.draws_pd(vars=['y_rep'], inc_warmup=False).shape == (
|
|
317
319
|
400,
|
|
318
|
-
|
|
320
|
+
10,
|
|
319
321
|
)
|
|
320
|
-
assert bern_gqs.draws_pd(vars='y_rep', inc_warmup=False).shape == (400,
|
|
322
|
+
assert bern_gqs.draws_pd(vars='y_rep', inc_warmup=False).shape == (400, 10)
|
|
321
323
|
|
|
322
324
|
theta = bern_gqs.stan_variable(var='theta')
|
|
323
325
|
assert theta.shape == (400,)
|
|
@@ -21,13 +21,21 @@ BERN_EXE = os.path.join(DATAFILES_PATH, 'bernoulli' + EXTENSION)
|
|
|
21
21
|
BERN_BASENAME = 'bernoulli'
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
@pytest.mark.parametrize(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
@pytest.mark.parametrize(
|
|
25
|
+
"sig_figs, expected, expected_unadjusted",
|
|
26
|
+
[
|
|
27
|
+
(
|
|
28
|
+
11,
|
|
29
|
+
["-7.0214667713", "-1.188472607"],
|
|
30
|
+
["-5.5395901199", "-1.4903938392"],
|
|
31
|
+
),
|
|
32
|
+
(3, ["-7.02", "-1.19"], ["-5.54", "-1.49"]),
|
|
33
|
+
(None, ["-7.02147", "-1.18847"], ["-5.53959", "-1.49039"]),
|
|
34
|
+
],
|
|
35
|
+
)
|
|
36
|
+
def test_lp_good(
|
|
37
|
+
sig_figs: Optional[int], expected: List[str], expected_unadjusted: List[str]
|
|
38
|
+
) -> None:
|
|
31
39
|
model = CmdStanModel(stan_file=BERN_STAN)
|
|
32
40
|
params = {"theta": 0.34903938392023830482}
|
|
33
41
|
out = model.log_prob(params, data=BERN_DATA, sig_figs=sig_figs)
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
+
import numpy as np
|
|
7
8
|
import pytest
|
|
8
9
|
|
|
9
10
|
import cmdstanpy
|
|
@@ -31,6 +32,8 @@ def test_pathfinder_outputs():
|
|
|
31
32
|
assert theta.shape == (draws,)
|
|
32
33
|
assert 0.23 < theta.mean() < 0.27
|
|
33
34
|
|
|
35
|
+
assert pathfinder.is_resampled
|
|
36
|
+
|
|
34
37
|
assert pathfinder.draws().shape == (draws, 3)
|
|
35
38
|
|
|
36
39
|
|
|
@@ -58,6 +61,8 @@ def test_single_pathfinder():
|
|
|
58
61
|
draws=draws,
|
|
59
62
|
)
|
|
60
63
|
|
|
64
|
+
assert not pathfinder.is_resampled
|
|
65
|
+
|
|
61
66
|
theta = pathfinder.theta
|
|
62
67
|
assert theta.shape == (draws,)
|
|
63
68
|
|
|
@@ -122,3 +127,28 @@ def test_pathfinder_init_sampling():
|
|
|
122
127
|
|
|
123
128
|
assert fit.chains == 4
|
|
124
129
|
assert fit.draws().shape == (1000, 4, 9)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_pathfinder_no_psis():
|
|
133
|
+
stan = DATAFILES_PATH / 'bernoulli.stan'
|
|
134
|
+
bern_model = cmdstanpy.CmdStanModel(stan_file=stan)
|
|
135
|
+
jdata = str(DATAFILES_PATH / 'bernoulli.data.json')
|
|
136
|
+
|
|
137
|
+
pathfinder = bern_model.pathfinder(data=jdata, psis_resample=False)
|
|
138
|
+
|
|
139
|
+
assert not pathfinder.is_resampled
|
|
140
|
+
assert pathfinder.draws().shape == (4000, 3)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_pathfinder_no_lp_calc():
|
|
144
|
+
stan = DATAFILES_PATH / 'bernoulli.stan'
|
|
145
|
+
bern_model = cmdstanpy.CmdStanModel(stan_file=stan)
|
|
146
|
+
jdata = str(DATAFILES_PATH / 'bernoulli.data.json')
|
|
147
|
+
|
|
148
|
+
pathfinder = bern_model.pathfinder(data=jdata, calculate_lp=False)
|
|
149
|
+
|
|
150
|
+
assert not pathfinder.is_resampled
|
|
151
|
+
assert pathfinder.draws().shape == (4000, 3)
|
|
152
|
+
n_lp_nan = np.sum(np.isnan(pathfinder.method_variables()['lp__']))
|
|
153
|
+
assert n_lp_nan < 4000 # some lp still calculated during pathfinder
|
|
154
|
+
assert n_lp_nan > 3000 # but most are not
|
|
@@ -778,24 +778,19 @@ def test_validate_good_run() -> None:
|
|
|
778
778
|
fit.runset.chains * fit.num_draws_sampling,
|
|
779
779
|
len(fit.column_names) + 3,
|
|
780
780
|
)
|
|
781
|
-
assert fit.draws_pd(vars=['theta']).shape == (400,
|
|
782
|
-
assert fit.draws_pd(vars=['lp__', 'theta']).shape == (400,
|
|
783
|
-
assert fit.draws_pd(vars=['theta', 'lp__']).shape == (400,
|
|
784
|
-
assert fit.draws_pd(vars='theta').shape == (400,
|
|
781
|
+
assert fit.draws_pd(vars=['theta']).shape == (400, 1)
|
|
782
|
+
assert fit.draws_pd(vars=['lp__', 'theta']).shape == (400, 2)
|
|
783
|
+
assert fit.draws_pd(vars=['theta', 'lp__']).shape == (400, 2)
|
|
784
|
+
assert fit.draws_pd(vars='theta').shape == (400, 1)
|
|
785
785
|
|
|
786
786
|
assert list(fit.draws_pd(vars=['theta', 'lp__']).columns) == [
|
|
787
|
-
'chain__',
|
|
788
|
-
'iter__',
|
|
789
|
-
'draw__',
|
|
790
787
|
'theta',
|
|
791
788
|
'lp__',
|
|
792
789
|
]
|
|
793
|
-
assert list(fit.draws_pd(vars=['lp__', 'theta']).columns) == [
|
|
794
|
-
'chain__',
|
|
795
|
-
'iter__',
|
|
796
|
-
'draw__',
|
|
790
|
+
assert list(fit.draws_pd(vars=['lp__', 'theta', 'iter__']).columns) == [
|
|
797
791
|
'lp__',
|
|
798
792
|
'theta',
|
|
793
|
+
'iter__',
|
|
799
794
|
]
|
|
800
795
|
|
|
801
796
|
summary = fit.summary()
|
|
@@ -854,7 +849,7 @@ def test_validate_big_run() -> None:
|
|
|
854
849
|
assert fit.step_size.shape == (2,)
|
|
855
850
|
assert fit.metric.shape == (2, 2095)
|
|
856
851
|
assert fit.draws().shape == (1000, 2, 2102)
|
|
857
|
-
assert fit.draws_pd(vars=['phi']).shape == (2000,
|
|
852
|
+
assert fit.draws_pd(vars=['phi']).shape == (2000, 2095)
|
|
858
853
|
with raises_nested(ValueError, r'Unknown variable: gamma'):
|
|
859
854
|
fit.draws_pd(vars=['gamma'])
|
|
860
855
|
|
|
@@ -1440,6 +1435,26 @@ def test_dont_save_warmup(caplog: pytest.LogCaptureFixture) -> None:
|
|
|
1440
1435
|
)
|
|
1441
1436
|
|
|
1442
1437
|
|
|
1438
|
+
def test_warmup_no_adapt() -> None:
|
|
1439
|
+
# we may want to have a "burn-in" period, even without adaptation
|
|
1440
|
+
stan = os.path.join(DATAFILES_PATH, 'bernoulli.stan')
|
|
1441
|
+
jdata = os.path.join(DATAFILES_PATH, 'bernoulli.data.json')
|
|
1442
|
+
|
|
1443
|
+
bern_model = CmdStanModel(stan_file=stan)
|
|
1444
|
+
bern_fit = bern_model.sample(
|
|
1445
|
+
data=jdata,
|
|
1446
|
+
chains=2,
|
|
1447
|
+
seed=12345,
|
|
1448
|
+
iter_warmup=200,
|
|
1449
|
+
iter_sampling=100,
|
|
1450
|
+
adapt_engaged=False,
|
|
1451
|
+
)
|
|
1452
|
+
|
|
1453
|
+
assert bern_fit.column_names == tuple(BERNOULLI_COLS)
|
|
1454
|
+
assert bern_fit.num_draws_sampling == 100
|
|
1455
|
+
assert bern_fit.draws().shape == (100, 2, len(BERNOULLI_COLS))
|
|
1456
|
+
|
|
1457
|
+
|
|
1443
1458
|
def test_sampler_diags() -> None:
|
|
1444
1459
|
stan = os.path.join(DATAFILES_PATH, 'bernoulli.stan')
|
|
1445
1460
|
jdata = os.path.join(DATAFILES_PATH, 'bernoulli.data.json')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|