Skip to content

Commit a7b904c

Browse files
committed
Update: foresee generation of antithetic pairs of random
1 parent a61b1db commit a7b904c

File tree

2 files changed

+31
-66
lines changed

2 files changed

+31
-66
lines changed

kaleidoscope/algorithms/randomize.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def __init__(
3232
m: int = 2,
3333
dist: Literal["normal", "lognormal", "chlorophyll"] = "normal",
3434
seed: np.ndarray | None = None,
35+
antithetic: bool = False,
3536
):
3637
"""
3738
Creates a new algorithm instance.
@@ -40,10 +41,12 @@ def __init__(
4041
:param m: The number of input data dimensions.
4142
:param dist: The type of measurement error distribution.
4243
:param seed: The root seed.
44+
:param antithetic: To generate antithetic pairs of random numbers.
4345
"""
4446
super().__init__(dtype, m, m)
4547
self._dist = dist
4648
self._root_seed = seed
49+
self._antithetic = antithetic
4750

4851
def chunks(self, *inputs: da.Array) -> tuple[int, ...] | None:
4952
return None
@@ -133,7 +136,7 @@ def _normal(
133136
"""
134137
Returns randomized values for normally distributed errors.
135138
"""
136-
z: Normal = DefaultNormal(seed)
139+
z: Normal = DefaultNormal(seed, self._antithetic)
137140
return x + u * z.randoms(np.empty(x.shape, x.dtype))
138141

139142
@property

kaleidoscope/generators.py

Lines changed: 27 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"""
55
This module provides random number generators.
66
"""
7-
from typing import Literal
87

98
import numpy as np
109
from numpy.random import BitGenerator
@@ -43,6 +42,24 @@ def default_generator(seed) -> Generator:
4342
)
4443

4544

45+
def conditional_negate(
46+
randoms: np.ndarray | float, condition: bool
47+
) -> np.ndarray | float:
48+
"""
49+
Negates the given random numbers when a condition is met.
50+
51+
:param randoms: The random numbers.
52+
:param condition: The condition.
53+
:return: The negated or original random numbers.
54+
"""
55+
if condition:
56+
if isinstance(randoms, np.ndarray):
57+
randoms[:] = -randoms[:]
58+
else:
59+
randoms = -randoms
60+
return randoms
61+
62+
4663
class DefaultGenerator(Generating):
4764
"""The default random number generator."""
4865

@@ -86,80 +103,25 @@ class DefaultNormal(Normal):
86103
"""The default normal random deviate."""
87104

88105
_g: Generator
89-
90-
def __init__(self, seed: int | np.ndarray | BitGenerator | None = None):
91-
"""
92-
Creates a new random deviate.
93-
94-
:param seed: The seed.
95-
"""
96-
self._g = default_generator(seed)
97-
98-
def random(self) -> float:
99-
return self._g.standard_normal()
100-
101-
def randoms(self, randoms: np.ndarray) -> np.ndarray:
102-
self._g.standard_normal(dtype=randoms.dtype, out=randoms)
103-
return randoms
104-
105-
106-
class DecileNormal(Normal):
107-
"""
108-
The decile normal random deviate.
109-
110-
Generates random deviates, which are uniformly distributed in a
111-
selected decile of the standard normal distribution.
112-
"""
113-
114-
_g: Generator
115-
116-
_q: np.ndarray
117-
"""The deciles of the normal distribution."""
118-
_s: int | Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
119-
"""The decile selector."""
106+
_antithetic: bool
120107

121108
def __init__(
122-
self, s: int, seed: int | np.ndarray | BitGenerator | None = None
109+
self,
110+
seed: int | np.ndarray | BitGenerator | None = None,
111+
antithetic: bool = False,
123112
):
124113
"""
125114
Creates a new random deviate.
126115
127-
:param s: The decile selector.
128116
:param seed: The seed.
117+
:param antithetic: To generate antithetic pairs of random numbers.
129118
"""
130-
self._s = s % 10
131119
self._g = default_generator(seed)
132-
self._q = np.array(
133-
[
134-
-3.09023,
135-
-1.28155,
136-
-0.841621,
137-
-0.524401,
138-
-0.253347,
139-
0.0,
140-
0.253347,
141-
0.524401,
142-
0.841621,
143-
1.28155,
144-
3.09023,
145-
]
146-
)
120+
self._antithetic = antithetic
147121

148122
def random(self) -> float:
149-
return (self.sup - self.inf) * self._g.random() + self.inf
123+
return conditional_negate(self._g.standard_normal(), self._antithetic)
150124

151125
def randoms(self, randoms: np.ndarray) -> np.ndarray:
152-
self._g.random(dtype=randoms.dtype, out=randoms)
153-
randoms *= self.sup - self.inf
154-
randoms += self.inf
155-
return randoms
156-
157-
@property
158-
def sup(self) -> float:
159-
"""Returns the supremum of the selected decile."""
160-
return self._q[self._s + 1]
161-
162-
@property
163-
def inf(self) -> float:
164-
"""Returns the infimum of the selected decile."""
165-
return self._q[self._s]
126+
self._g.standard_normal(dtype=randoms.dtype, out=randoms)
127+
return conditional_negate(randoms, self._antithetic)

0 commit comments

Comments
 (0)