Skip to content

Commit 6e072f3

Browse files
committed
Merge branch 'develop' of https://github.com/stan-dev/cmdstanpy into develop
2 parents fbf4938 + 8ad7a9f commit 6e072f3

19 files changed

Lines changed: 535 additions & 410 deletions

.pylintrc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,9 @@ disable=bad-continuation,
7373
too-many-branches,
7474
too-many-locals,
7575
unsubscriptable-object,
76-
consider-using-with
77-
78-
79-
76+
consider-using-with,
77+
consider-using-dict-items,
78+
unspecified-encoding,
8079

8180
# Enable the message, report, category or checker with the given id(s). You can
8281
# either give multiple identifier separated by comma (,) or put this option

.readthedocs.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@ version: 2
33
build:
44
image: stable
55

6+
formats:
7+
- pdf
8+
69
conda:
710
environment: docsrc/env.yml

README.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,20 @@ The CmdStanPy, CmdStan, and the core Stan C++ code are licensed under new BSD.
3737

3838
### Example
3939

40-
::
40+
```python
41+
import os
42+
from cmdstanpy import cmdstan_path, CmdStanModel
4143

42-
import os
43-
from cmdstanpy import cmdstan_path, CmdStanModel
44+
# specify locations of Stan program file and data
45+
stan_file = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.stan')
46+
data_file = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.data.json')
4447

45-
# specify locations of Stan program file and data
46-
bernoulli_stan = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.stan')
47-
bernoulli_data = os.path.join(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.data.json')
48+
# instantiate a model; compiles the Stan program by default
49+
model = CmdStanModel(stan_file=stan_file)
4850

49-
# instantiate a model; compiles the Stan program by default
50-
bernoulli_model = CmdStanModel(stan_file=bernoulli_stan)
51+
# obtain a posterior sample from the model conditioned on the data
52+
fit = model.sample(chains=4, data=data_file)
5153

52-
# obtain a posterior sample from the model conditioned on the data
53-
bernoulli_fit = bernoulli_model.sample(chains=4, data=bernoulli_data)
54-
55-
# summarize the results (wraps CmdStan `bin/stansummary`):
56-
bernoulli_fit.summary()
54+
# summarize the results (wraps CmdStan `bin/stansummary`):
55+
fit.summary()
56+
```

cmdstanpy/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,13 @@ def _cleanup_tmpdir() -> None:
4646
from_csv,
4747
)
4848
from .utils import set_cmdstan_path # noqa
49-
from .utils import cmdstan_path, install_cmdstan, set_make_env, write_stan_json
49+
from .utils import (
50+
cmdstan_path,
51+
install_cmdstan,
52+
set_make_env,
53+
show_versions,
54+
write_stan_json,
55+
)
5056

5157
__all__ = [
5258
'set_cmdstan_path',
@@ -61,4 +67,5 @@ def _cleanup_tmpdir() -> None:
6167
'InferenceMetadata',
6268
'from_csv',
6369
'write_stan_json',
70+
'show_versions',
6471
]

cmdstanpy/cmdstan_args.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ def validate(self, chains: Optional[int]) -> None:
159159
self.metric = 'diag_e'
160160
elif self.metric in ['dense', 'dense_e']:
161161
self.metric = 'dense_e'
162+
elif self.metric in ['unit', 'unit_e']:
163+
self.metric = 'unit_e'
162164
else:
163165
if not os.path.exists(self.metric):
164166
raise ValueError('no such file {}'.format(self.metric))
@@ -638,7 +640,7 @@ def __init__(
638640
inits: Union[int, float, str, List[str], None] = None,
639641
output_dir: Optional[str] = None,
640642
sig_figs: Optional[int] = None,
641-
save_diagnostics: bool = False,
643+
save_latent_dynamics: bool = False,
642644
save_profile: bool = False,
643645
refresh: Optional[int] = None,
644646
logger: Optional[logging.Logger] = None,
@@ -652,7 +654,7 @@ def __init__(
652654
self.inits = inits
653655
self.output_dir = output_dir
654656
self.sig_figs = sig_figs
655-
self.save_diagnostics = save_diagnostics
657+
self.save_latent_dynamics = save_latent_dynamics
656658
self.save_profile = save_profile
657659
self.refresh = refresh
658660
self.method_args = method_args

cmdstanpy/model.py

Lines changed: 64 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -344,17 +344,12 @@ def compile(
344344
)
345345
if 'PCH file' in str(e):
346346
get_logger().warning(
347-
"%s, %s",
348-
"CmdStan's precompiled header (PCH) files ",
349-
"may need to be rebuilt.",
350-
)
351-
get_logger().warning(
352-
"%s %s",
353-
"If your model failed to compile please run ",
354-
"install_cmdstan(overwrite=True).",
355-
)
356-
get_logger().warning(
357-
"If the issue persists please open a bug report"
347+
"%s",
348+
"CmdStan's precompiled header (PCH) files "
349+
"may need to be rebuilt."
350+
"If your model failed to compile please run "
351+
"install_cmdstan(overwrite=True).\nIf the "
352+
"issue persists please open a bug report",
358353
)
359354

360355
compilation_failed = True
@@ -398,6 +393,7 @@ def optimize(
398393
history_size: Optional[int] = None,
399394
iter: Optional[int] = None,
400395
refresh: Optional[int] = None,
396+
time_fmt: str = "%Y%m%d%H%M%S",
401397
) -> CmdStanMLE:
402398
"""
403399
Run the specified CmdStan optimize algorithm to produce a
@@ -410,7 +406,7 @@ def optimize(
410406
those arguments will have CmdStan default values.
411407
412408
The :class:`CmdStanMLE` object records the command, the return code,
413-
and the paths to the optimize method output csv and console files.
409+
and the paths to the optimize method output CSV and console files.
414410
The output files are written either to a specified output directory
415411
or to a temporary directory which is deleted upon session exit.
416412
@@ -454,7 +450,7 @@ def optimize(
454450
Introduced in CmdStan-2.25.
455451
456452
:param save_profile: Whether or not to profile auto-diff operations in
457-
labelled blocks of code. If True, csv outputs are written to a file
453+
labelled blocks of code. If True, CSV outputs are written to a file
458454
'<model_name>-<YYYYMMDDHHMM>-profile-<chain_id>'.
459455
Introduced in CmdStan-2.26.
460456
@@ -484,6 +480,10 @@ def optimize(
484480
:param refresh: Specify the number of iterations cmdstan will take
485481
between progress messages. Default value is 100.
486482
483+
:param time_fmt: A format string passed to
484+
:meth:`~datetime.datetime.strftime` to decide the file names for
485+
output CSVs. Defaults to "%Y%m%d%H%M%S"
486+
487487
:return: CmdStanMLE object
488488
"""
489489
optimize_args = OptimizeArgs(
@@ -514,7 +514,7 @@ def optimize(
514514
)
515515

516516
dummy_chain_id = 0
517-
runset = RunSet(args=args, chains=1)
517+
runset = RunSet(args=args, chains=1, time_fmt=time_fmt)
518518
self._run_cmdstan(runset, dummy_chain_id)
519519

520520
if not runset._check_retcodes():
@@ -551,10 +551,11 @@ def sample(
551551
fixed_param: bool = False,
552552
output_dir: Optional[str] = None,
553553
sig_figs: Optional[int] = None,
554-
save_diagnostics: bool = False,
554+
save_latent_dynamics: bool = False,
555555
save_profile: bool = False,
556556
show_progress: Union[bool, str] = False,
557557
refresh: Optional[int] = None,
558+
time_fmt: str = "%Y%m%d%H%M%S",
558559
) -> CmdStanMCMC:
559560
"""
560561
Run or more chains of the NUTS-HMC sampler to produce a set of draws
@@ -627,7 +628,7 @@ def sample(
627628
chain.
628629
629630
:param save_warmup: When ``True``, sampler saves warmup draws as part of
630-
the Stan csv output file.
631+
the Stan CSV output file.
631632
632633
:param thin: Period between recorded iterations. Default is 1, i.e.,
633634
all iterations are recorded.
@@ -696,16 +697,20 @@ def sample(
696697
precision for the system file I/O is used; the usual value is 6.
697698
Introduced in CmdStan-2.25.
698699
699-
:param save_diagnostics: Whether or not to output the position and
700-
momentum information for each parameter. If True,
701-
csv outputs are written to an output file using filename
700+
:param save_latent_dynamics: Whether or not to output the position and
701+
momentum information for the model parameters (unconstrained).
702+
If True, CSV outputs are written to an output file using filename
702703
template '<model_name>-<YYYYMMDDHHMM>-diagnostic-<chain_id>',
703-
e.g. 'bernoulli-201912081451-diagnostic-1.csv'.
704+
e.g. 'bernoulli-201912081451-diagnostic-1.csv', see
705+
https://mc-stan.org/docs/cmdstan-guide/stan-csv.html,
706+
section "Diagnostic CSV output file" for details.
704707
705708
:param save_profile: Whether or not to profile auto-diff operations in
706-
labelled blocks of code. If True, csv outputs are written to a file
709+
labelled blocks of code. If True, CSV outputs are written to a file
707710
'<model_name>-<YYYYMMDDHHMM>-profile-<chain_id>'.
708-
Introduced in CmdStan-2.26.
711+
Introduced in CmdStan-2.26, see
712+
https://mc-stan.org/docs/cmdstan-guide/stan-csv.html,
713+
section "Profiling CSV output file" for details.
709714
710715
:param show_progress: Use tqdm progress bar to show sampling progress.
711716
If show_progress=='notebook' use tqdm_notebook
@@ -714,6 +719,10 @@ def sample(
714719
:param refresh: Specify the number of iterations cmdstan will take
715720
between progress messages. Default value is 100.
716721
722+
:param time_fmt: A format string passed to
723+
:meth:`~datetime.datetime.strftime` to decide the file names for
724+
output CSVs. Defaults to "%Y%m%d%H%M%S"
725+
717726
:return: CmdStanMCMC object
718727
"""
719728
if chains is None:
@@ -820,12 +829,14 @@ def sample(
820829
inits=_inits,
821830
output_dir=output_dir,
822831
sig_figs=sig_figs,
823-
save_diagnostics=save_diagnostics,
832+
save_latent_dynamics=save_latent_dynamics,
824833
save_profile=save_profile,
825834
method_args=sampler_args,
826835
refresh=refresh,
827836
)
828-
runset = RunSet(args=args, chains=chains, chain_ids=chain_ids)
837+
runset = RunSet(
838+
args=args, chains=chains, chain_ids=chain_ids, time_fmt=time_fmt
839+
)
829840
pbar = None
830841
all_pbars = []
831842

@@ -895,6 +906,7 @@ def generate_quantities(
895906
gq_output_dir: Optional[str] = None,
896907
sig_figs: Optional[int] = None,
897908
refresh: Optional[int] = None,
909+
time_fmt: str = "%Y%m%d%H%M%S",
898910
) -> CmdStanGQ:
899911
"""
900912
Run CmdStan's generate_quantities method which runs the generated
@@ -905,7 +917,7 @@ def generate_quantities(
905917
method to generate additional quantities of interest.
906918
907919
The :class:`CmdStanGQ` object records the command, the return code,
908-
and the paths to the generate method output csv and console files.
920+
and the paths to the generate method output CSV and console files.
909921
The output files are written either to a specified output directory
910922
or to a temporary directory which is deleted upon session exit.
911923
@@ -946,6 +958,10 @@ def generate_quantities(
946958
:param refresh: Specify the number of iterations cmdstan will take
947959
between progress messages. Default value is 100.
948960
961+
:param time_fmt: A format string passed to
962+
:meth:`~datetime.datetime.strftime` to decide the file names for
963+
output CSVs. Defaults to "%Y%m%d%H%M%S"
964+
949965
:return: CmdStanGQ object
950966
"""
951967
if isinstance(mcmc_sample, CmdStanMCMC):
@@ -995,7 +1011,9 @@ def generate_quantities(
9951011
method_args=generate_quantities_args,
9961012
refresh=refresh,
9971013
)
998-
runset = RunSet(args=args, chains=chains, chain_ids=chain_ids)
1014+
runset = RunSet(
1015+
args=args, chains=chains, chain_ids=chain_ids, time_fmt=time_fmt
1016+
)
9991017

10001018
parallel_chains_avail = cpu_count()
10011019
parallel_chains = max(min(parallel_chains_avail - 2, chains), 1)
@@ -1021,7 +1039,7 @@ def variational(
10211039
inits: Optional[float] = None,
10221040
output_dir: Optional[str] = None,
10231041
sig_figs: Optional[int] = None,
1024-
save_diagnostics: bool = False,
1042+
save_latent_dynamics: bool = False,
10251043
save_profile: bool = False,
10261044
algorithm: Optional[str] = None,
10271045
iter: Optional[int] = None,
@@ -1035,6 +1053,7 @@ def variational(
10351053
output_samples: Optional[int] = None,
10361054
require_converged: bool = True,
10371055
refresh: Optional[int] = None,
1056+
time_fmt: str = "%Y%m%d%H%M%S",
10381057
) -> CmdStanVB:
10391058
"""
10401059
Run CmdStan's variational inference algorithm to approximate
@@ -1047,7 +1066,7 @@ def variational(
10471066
those arguments will have CmdStan default values.
10481067
10491068
The :class:`CmdStanVB` object records the command, the return code,
1050-
and the paths to the variational method output csv and console files.
1069+
and the paths to the variational method output CSV and console files.
10511070
The output files are written either to a specified output directory
10521071
or to a temporary directory which is deleted upon session exit.
10531072
@@ -1082,13 +1101,13 @@ def variational(
10821101
precision for the system file I/O is used; the usual value is 6.
10831102
Introduced in CmdStan-2.25.
10841103
1085-
:param save_diagnostics: Whether or not to save diagnostics. If True,
1086-
csv outputs are written to an output file using filename
1104+
:param save_latent_dynamics: Whether or not to save diagnostics.
1105+
If True, CSV outputs are written to an output file using filename
10871106
template '<model_name>-<YYYYMMDDHHMM>-diagnostic-<chain_id>',
10881107
e.g. 'bernoulli-201912081451-diagnostic-1.csv'.
10891108
10901109
:param save_profile: Whether or not to profile auto-diff operations in
1091-
labelled blocks of code. If True, csv outputs are written to a file
1110+
labelled blocks of code. If True, CSV outputs are written to a file
10921111
'<model_name>-<YYYYMMDDHHMM>-profile-<chain_id>'.
10931112
Introduced in CmdStan-2.26.
10941113
@@ -1119,6 +1138,10 @@ def variational(
11191138
:param refresh: Specify the number of iterations cmdstan will take
11201139
between progress messages. Default value is 100.
11211140
1141+
:param time_fmt: A format string passed to
1142+
:meth:`~datetime.datetime.strftime` to decide the file names for
1143+
output CSVs. Defaults to "%Y%m%d%H%M%S"
1144+
11221145
:return: CmdStanVB object
11231146
"""
11241147
variational_args = VariationalArgs(
@@ -1144,14 +1167,14 @@ def variational(
11441167
inits=_inits,
11451168
output_dir=output_dir,
11461169
sig_figs=sig_figs,
1147-
save_diagnostics=save_diagnostics,
1170+
save_latent_dynamics=save_latent_dynamics,
11481171
save_profile=save_profile,
11491172
method_args=variational_args,
11501173
refresh=refresh,
11511174
)
11521175

11531176
dummy_chain_id = 0
1154-
runset = RunSet(args=args, chains=1)
1177+
runset = RunSet(args=args, chains=1, time_fmt=time_fmt)
11551178
self._run_cmdstan(runset, dummy_chain_id)
11561179

11571180
# treat failure to converge as failure
@@ -1238,11 +1261,16 @@ def _run_cmdstan(
12381261
msg = 'Chain {} terminated by signal {}'.format(
12391262
idx + 1, proc.returncode
12401263
)
1241-
else:
1264+
elif proc.returncode < 125:
12421265
msg = 'Chain {} processing error'.format(idx + 1)
1243-
msg = '{}, non-zero return code {}'.format(
1244-
msg, proc.returncode
1266+
msg = '{}, return code {}'.format(msg, proc.returncode)
1267+
elif proc.returncode > 128:
1268+
msg = 'Chain {} system error'.format(idx + 1)
1269+
msg = '{}, terminated by signal {}'.format(
1270+
msg, proc.returncode - 128
12451271
)
1272+
else:
1273+
msg = 'Chain {} unknown error'.format(idx + 1)
12461274
if len(console_error) > 0:
12471275
msg = '{}\n error message:\n\t{}'.format(msg, console_error)
12481276
get_logger().error(msg)

0 commit comments

Comments
 (0)