|
4 | 4 | from typing import Generator, Tuple, cast |
5 | 5 |
|
6 | 6 | import numpy as np |
7 | | -import simdjson |
| 7 | +import orjson |
8 | 8 |
|
9 | 9 |
|
10 | 10 | class Fit(collections.abc.Mapping): |
@@ -65,43 +65,38 @@ def __init__( |
65 | 65 | # _draws is an ndarray with shape (num_sample_and_sampler_params + num_flat_params, num_draws, num_chains) |
66 | 66 | self._draws: np.ndarray |
67 | 67 |
|
68 | | - parser = simdjson.Parser() |
69 | 68 | for chain_index, stan_output in zip(range(self.num_chains), self.stan_outputs): |
70 | 69 | draw_index = 0 |
71 | 70 | for line in stan_output.splitlines(): |
72 | 71 | try: |
73 | | - msg = cast(simdjson.Object, parser.parse(line)) |
74 | | - except ValueError: |
75 | | - # Occurs when draws contain an nan or infinity. simdjson cannot parse such values. |
| 72 | + msg = orjson.loads(line) |
| 73 | + except orjson.JSONDecodeError: |
| 74 | + # Occurs when draws contain a NaN or infinity. orjson cannot parse such values. |
76 | 75 | msg = json.loads(line) |
77 | | - try: |
78 | | - if msg["topic"] == "sample": |
79 | | - # Ignore sample message which is mixed together with proper draws. |
80 | | - if not isinstance(msg["values"], (simdjson.Object, dict)): |
81 | | - continue |
82 | | - |
83 | | - # for the first draw: collect sample and sampler parameter names. |
84 | | - if not hasattr(self, "_draws"): |
85 | | - feature_names = cast(Tuple[str, ...], tuple(msg["values"].keys())) |
86 | | - self.sample_and_sampler_param_names = tuple( |
87 | | - name for name in feature_names if name.endswith("__") |
| 76 | + if msg["topic"] == "sample": |
| 77 | + # Ignore sample message which is mixed together with proper draws. |
| 78 | + if not isinstance(msg["values"], dict): |
| 79 | + continue |
| 80 | + |
| 81 | + # for the first draw: collect sample and sampler parameter names. |
| 82 | + if not hasattr(self, "_draws"): |
| 83 | + feature_names = cast(Tuple[str, ...], tuple(msg["values"].keys())) |
| 84 | + self.sample_and_sampler_param_names = tuple( |
| 85 | + name for name in feature_names if name.endswith("__") |
| 86 | + ) |
| 87 | + num_rows = len(self.sample_and_sampler_param_names) + num_flat_params |
| 88 | + # column-major order ("F") aligns with how the draws are stored (in cols). |
| 89 | + self._draws = np.empty((num_rows, num_samples_saved, num_chains), order="F") |
| 90 | + # rudimentary check of parameter order (sample & sampler params must be first) |
| 91 | + if num_flat_params and feature_names[-1].endswith("__"): |
| 92 | + raise RuntimeError( |
| 93 | + f"Expected last parameter name to be one declared in program code, found `{feature_names[-1]}`" |
88 | 94 | ) |
89 | | - num_rows = len(self.sample_and_sampler_param_names) + num_flat_params |
90 | | - # column-major order ("F") aligns with how the draws are stored (in cols). |
91 | | - self._draws = np.empty((num_rows, num_samples_saved, num_chains), order="F") |
92 | | - # rudimentary check of parameter order (sample & sampler params must be first) |
93 | | - if num_flat_params and feature_names[-1].endswith("__"): |
94 | | - raise RuntimeError( |
95 | | - f"Expected last parameter name to be one declared in program code, found `{feature_names[-1]}`" |
96 | | - ) |
97 | | - |
98 | | - draw_row = tuple(msg["values"].values()) # a "row" of values from a single draw from Stan C++ |
99 | | - draw_row = cast(Tuple[float, ...], draw_row) |
100 | | - self._draws[:, draw_index, chain_index] = draw_row |
101 | | - draw_index += 1 |
102 | | - finally: |
103 | | - # clean up `Object`s produced by parser, required by simdjson |
104 | | - del msg |
| 95 | + |
| 96 | + draw_row = tuple(msg["values"].values()) # a "row" of values from a single draw from Stan C++ |
| 97 | + draw_row = cast(Tuple[float, ...], draw_row) |
| 98 | + self._draws[:, draw_index, chain_index] = draw_row |
| 99 | + draw_index += 1 |
105 | 100 | assert draw_index == num_samples_saved |
106 | 101 | assert self.sample_and_sampler_param_names and self._draws.size |
107 | 102 | self._draws.flags["WRITEABLE"] = False # type: ignore |
|
0 commit comments