|
11 | 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12 | 12 | # See the License for the specific language governing permissions and
|
13 | 13 | # limitations under the License.
|
14 |
| -from typing import Any, Callable, Dict, List, Tuple |
| 14 | +from typing import Any, Callable, Dict, List, Optional, Tuple |
15 | 15 |
|
16 | 16 | import numpy as np
|
17 | 17 | import numpy.random as nr
|
|
50 | 50 |
|
51 | 51 |
|
52 | 52 | class Proposal:
|
53 |
| - def __init__(self, s): |
| 53 | + def __init__(self, s, rng_seed: Optional[int] = None): |
54 | 54 | self.s = s
|
| 55 | + self.rng = np.random.default_rng(rng_seed) |
55 | 56 |
|
56 | 57 |
|
57 | 58 | class NormalProposal(Proposal):
|
58 |
| - def __call__(self): |
59 |
| - return nr.normal(scale=self.s) |
| 59 | + def __call__(self, rng: Optional[np.random.Generator] = None): |
| 60 | + if rng is None: |
| 61 | + rng = self.rng |
| 62 | + return rng.normal(scale=self.s) |
60 | 63 |
|
61 | 64 |
|
62 | 65 | class UniformProposal(Proposal):
|
63 |
| - def __call__(self): |
64 |
| - return nr.uniform(low=-self.s, high=self.s, size=len(self.s)) |
| 66 | + def __call__(self, rng: Optional[np.random.Generator] = None): |
| 67 | + if rng is None: |
| 68 | + rng = self.rng |
| 69 | + return rng.uniform(low=-self.s, high=self.s, size=len(self.s)) |
65 | 70 |
|
66 | 71 |
|
67 | 72 | class CauchyProposal(Proposal):
|
68 |
| - def __call__(self): |
69 |
| - return nr.standard_cauchy(size=np.size(self.s)) * self.s |
| 73 | + def __call__(self, rng: Optional[np.random.Generator] = None): |
| 74 | + if rng is None: |
| 75 | + rng = self.rng |
| 76 | + return rng.standard_cauchy(size=np.size(self.s)) * self.s |
70 | 77 |
|
71 | 78 |
|
72 | 79 | class LaplaceProposal(Proposal):
|
73 |
| - def __call__(self): |
| 80 | + def __call__(self, rng: Optional[np.random.Generator] = None): |
| 81 | + if rng is None: |
| 82 | + rng = self.rng |
74 | 83 | size = np.size(self.s)
|
75 |
| - return (nr.standard_exponential(size=size) - nr.standard_exponential(size=size)) * self.s |
| 84 | + return (rng.standard_exponential(size=size) - rng.standard_exponential(size=size)) * self.s |
76 | 85 |
|
77 | 86 |
|
78 | 87 | class PoissonProposal(Proposal):
|
79 |
| - def __call__(self): |
80 |
| - return nr.poisson(lam=self.s, size=np.size(self.s)) - self.s |
| 88 | + def __call__(self, rng: Optional[np.random.Generator] = None): |
| 89 | + if rng is None: |
| 90 | + rng = self.rng |
| 91 | + return rng.poisson(lam=self.s, size=np.size(self.s)) - self.s |
81 | 92 |
|
82 | 93 |
|
83 | 94 | class MultivariateNormalProposal(Proposal):
|
84 |
| - def __init__(self, s): |
85 |
| - n, m = s.shape |
| 95 | + def __init__(self, *args, **kwargs): |
| 96 | + super().__init__(*args, **kwargs) |
| 97 | + n, m = self.s.shape |
86 | 98 | if n != m:
|
87 | 99 | raise ValueError("Covariance matrix is not symmetric.")
|
88 | 100 | self.n = n
|
89 |
| - self.chol = scipy.linalg.cholesky(s, lower=True) |
| 101 | + self.chol = scipy.linalg.cholesky(self.s, lower=True) |
90 | 102 |
|
91 |
| - def __call__(self, num_draws=None): |
| 103 | + def __call__(self, num_draws=None, rng: Optional[np.random.Generator] = None): |
| 104 | + if rng is None: |
| 105 | + rng = self.rng |
92 | 106 | if num_draws is not None:
|
93 |
| - b = np.random.randn(self.n, num_draws) |
| 107 | + b = rng.normal(size=(self.n, num_draws)) |
94 | 108 | return np.dot(self.chol, b).T
|
95 | 109 | else:
|
96 |
| - b = np.random.randn(self.n) |
| 110 | + b = rng.normal(size=self.n) |
97 | 111 | return np.dot(self.chol, b)
|
98 | 112 |
|
99 | 113 |
|
|
0 commit comments