humalab 0.1.0__py3-none-any.whl
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.
- humalab/__init__.py +34 -0
- humalab/assets/__init__.py +10 -0
- humalab/assets/archive.py +101 -0
- humalab/assets/files/__init__.py +4 -0
- humalab/assets/files/resource_file.py +131 -0
- humalab/assets/files/urdf_file.py +103 -0
- humalab/assets/resource_operator.py +139 -0
- humalab/constants.py +50 -0
- humalab/dists/__init__.py +24 -0
- humalab/dists/bernoulli.py +84 -0
- humalab/dists/categorical.py +81 -0
- humalab/dists/discrete.py +103 -0
- humalab/dists/distribution.py +49 -0
- humalab/dists/gaussian.py +96 -0
- humalab/dists/log_uniform.py +97 -0
- humalab/dists/truncated_gaussian.py +129 -0
- humalab/dists/uniform.py +95 -0
- humalab/episode.py +306 -0
- humalab/humalab.py +219 -0
- humalab/humalab_api_client.py +966 -0
- humalab/humalab_config.py +122 -0
- humalab/humalab_test.py +527 -0
- humalab/metrics/__init__.py +17 -0
- humalab/metrics/code.py +59 -0
- humalab/metrics/metric.py +96 -0
- humalab/metrics/scenario_stats.py +163 -0
- humalab/metrics/summary.py +75 -0
- humalab/run.py +325 -0
- humalab/scenarios/__init__.py +11 -0
- humalab/scenarios/scenario.py +375 -0
- humalab/scenarios/scenario_operator.py +114 -0
- humalab/scenarios/scenario_test.py +792 -0
- humalab/utils.py +37 -0
- humalab-0.1.0.dist-info/METADATA +43 -0
- humalab-0.1.0.dist-info/RECORD +39 -0
- humalab-0.1.0.dist-info/WHEEL +5 -0
- humalab-0.1.0.dist-info/entry_points.txt +2 -0
- humalab-0.1.0.dist-info/licenses/LICENSE +21 -0
- humalab-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from humalab.dists.distribution import Distribution
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
class Categorical(Distribution):
|
|
6
|
+
"""Categorical distribution for discrete choices.
|
|
7
|
+
|
|
8
|
+
Samples from a list of choices with optional weights. If weights are not
|
|
9
|
+
provided, samples uniformly from all choices. Weights are automatically
|
|
10
|
+
normalized to sum to 1.
|
|
11
|
+
"""
|
|
12
|
+
def __init__(self,
|
|
13
|
+
generator: np.random.Generator,
|
|
14
|
+
choices: list,
|
|
15
|
+
weights: list[float] | None = None,
|
|
16
|
+
size: int | tuple[int, ...] | None = None) -> None:
|
|
17
|
+
"""
|
|
18
|
+
Initialize the categorical distribution.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
generator (np.random.Generator): The random number generator.
|
|
22
|
+
choices (list): The list of choices.
|
|
23
|
+
weights (list[float] | None): The weights for each choice.
|
|
24
|
+
size (int | tuple[int, ...] | None): The size of the output.
|
|
25
|
+
"""
|
|
26
|
+
super().__init__(generator=generator)
|
|
27
|
+
self._choices = choices
|
|
28
|
+
self._size = size
|
|
29
|
+
if weights is not None and not np.isclose(sum(weights), 1.0):
|
|
30
|
+
weight_sum = sum(weights)
|
|
31
|
+
weights = [w / weight_sum for w in weights]
|
|
32
|
+
self._weights = weights
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def validate(dimensions: int, *args) -> bool:
|
|
36
|
+
"""Validate distribution parameters for the given dimensions.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
dimensions (int): The number of dimensions (0 for scalar, -1 for any).
|
|
40
|
+
*args: The distribution parameters (choices, weights).
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
bool: Always returns True as categorical accepts any parameters.
|
|
44
|
+
"""
|
|
45
|
+
return True
|
|
46
|
+
|
|
47
|
+
def _sample(self) -> int | float | np.ndarray:
|
|
48
|
+
"""Generate a sample from the categorical distribution.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
int | float | np.ndarray: Sampled choice(s) from the list.
|
|
52
|
+
"""
|
|
53
|
+
return self._generator.choice(self._choices, size=self._size, p=self._weights)
|
|
54
|
+
|
|
55
|
+
def __repr__(self) -> str:
|
|
56
|
+
"""String representation of the categorical distribution.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
str: String representation showing choices, size, and weights.
|
|
60
|
+
"""
|
|
61
|
+
return f"Categorical(choices={self._choices}, size={self._size}, weights={self._weights})"
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def create(generator: np.random.Generator,
|
|
65
|
+
choices: list,
|
|
66
|
+
weights: list[float] | None = None,
|
|
67
|
+
size: int | tuple[int, ...] | None = None
|
|
68
|
+
) -> 'Categorical':
|
|
69
|
+
"""
|
|
70
|
+
Create a categorical distribution.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
generator (np.random.Generator): The random number generator.
|
|
74
|
+
choices (list): The list of choices.
|
|
75
|
+
size (int | tuple[int, ...] | None): The size of the output.
|
|
76
|
+
weights (list[float] | None): The weights for each choice.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Categorical: The created categorical distribution.
|
|
80
|
+
"""
|
|
81
|
+
return Categorical(generator=generator, choices=choices, size=size, weights=weights)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from humalab.dists.distribution import Distribution
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
class Discrete(Distribution):
|
|
7
|
+
"""Discrete uniform distribution over integers.
|
|
8
|
+
|
|
9
|
+
Samples integer values uniformly from a range [low, high). The endpoint
|
|
10
|
+
parameter controls whether the upper bound is inclusive or exclusive.
|
|
11
|
+
Supports scalar outputs as well as multi-dimensional arrays with 1D variants.
|
|
12
|
+
"""
|
|
13
|
+
def __init__(self,
|
|
14
|
+
generator: np.random.Generator,
|
|
15
|
+
low: int | Any,
|
|
16
|
+
high: int | Any,
|
|
17
|
+
endpoint: bool | None = None,
|
|
18
|
+
size: int | tuple[int, ...] | None = None,
|
|
19
|
+
) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Initialize the discrete distribution.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
generator (np.random.Generator): The random number generator.
|
|
25
|
+
low (int | Any): The lower bound (inclusive).
|
|
26
|
+
high (int | Any): The upper bound (exclusive).
|
|
27
|
+
endpoint (bool | None): Whether to include the endpoint.
|
|
28
|
+
size (int | tuple[int, ...] | None): The size of the output.
|
|
29
|
+
"""
|
|
30
|
+
super().__init__(generator=generator)
|
|
31
|
+
self._low = np.array(low)
|
|
32
|
+
self._high = np.array(high)
|
|
33
|
+
self._size = size
|
|
34
|
+
self._endpoint = endpoint if endpoint is not None else True
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def validate(dimensions: int, *args) -> bool:
|
|
38
|
+
"""Validate distribution parameters for the given dimensions.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
dimensions (int): The number of dimensions (0 for scalar, -1 for any).
|
|
42
|
+
*args: The distribution parameters (low, high).
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
bool: True if parameters are valid, False otherwise.
|
|
46
|
+
"""
|
|
47
|
+
arg1 = args[0]
|
|
48
|
+
arg2 = args[1]
|
|
49
|
+
if dimensions == 0:
|
|
50
|
+
if not isinstance(arg1, int):
|
|
51
|
+
return False
|
|
52
|
+
if not isinstance(arg2, int):
|
|
53
|
+
return False
|
|
54
|
+
return True
|
|
55
|
+
if dimensions == -1:
|
|
56
|
+
return True
|
|
57
|
+
if not isinstance(arg1, int):
|
|
58
|
+
if isinstance(arg1, (list, np.ndarray)):
|
|
59
|
+
if len(arg1) != dimensions:
|
|
60
|
+
return False
|
|
61
|
+
if not isinstance(arg2, int):
|
|
62
|
+
if isinstance(arg2, (list, np.ndarray)):
|
|
63
|
+
if len(arg2) != dimensions:
|
|
64
|
+
return False
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
def _sample(self) -> int | float | np.ndarray:
|
|
68
|
+
"""Generate a sample from the discrete distribution.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
int | float | np.ndarray: Sampled integer value(s) from [low, high).
|
|
72
|
+
"""
|
|
73
|
+
return self._generator.integers(self._low, self._high, size=self._size, endpoint=self._endpoint)
|
|
74
|
+
|
|
75
|
+
def __repr__(self) -> str:
|
|
76
|
+
"""String representation of the discrete distribution.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
str: String representation showing low, high, size, and endpoint.
|
|
80
|
+
"""
|
|
81
|
+
return f"Discrete(low={self._low}, high={self._high}, size={self._size}, endpoint={self._endpoint})"
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def create(generator: np.random.Generator,
|
|
85
|
+
low: int | Any,
|
|
86
|
+
high: int | Any,
|
|
87
|
+
endpoint: bool = True,
|
|
88
|
+
size: int | tuple[int, ...] | None = None,
|
|
89
|
+
) -> 'Discrete':
|
|
90
|
+
"""
|
|
91
|
+
Create a discrete distribution.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
generator (np.random.Generator): The random number generator.
|
|
95
|
+
low (int | Any): The lower bound (inclusive).
|
|
96
|
+
high (int | Any): The upper bound (exclusive).
|
|
97
|
+
endpoint (bool): Whether to include the endpoint.
|
|
98
|
+
size (int | tuple[int, ...] | None): The size of the output.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Discrete: The created discrete distribution.
|
|
102
|
+
"""
|
|
103
|
+
return Discrete(generator=generator, low=low, high=high, size=size, endpoint=endpoint)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
class Distribution(ABC):
|
|
6
|
+
"""Abstract base class for probability distributions.
|
|
7
|
+
|
|
8
|
+
All distribution classes inherit from this base class and must implement
|
|
9
|
+
the _sample() method. Distributions maintain a random number generator
|
|
10
|
+
and track the last sampled value.
|
|
11
|
+
"""
|
|
12
|
+
def __init__(self,
|
|
13
|
+
generator: np.random.Generator) -> None:
|
|
14
|
+
"""
|
|
15
|
+
Initialize the distribution.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
generator (np.random.Generator): The random number generator.
|
|
19
|
+
"""
|
|
20
|
+
super().__init__()
|
|
21
|
+
self._generator = generator
|
|
22
|
+
self._last_sample = None
|
|
23
|
+
|
|
24
|
+
def sample(self) -> int | float | np.ndarray:
|
|
25
|
+
"""
|
|
26
|
+
Sample from the distribution.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
int | float | np.ndarray: The sampled value(s).
|
|
30
|
+
"""
|
|
31
|
+
self._last_sample = self._sample()
|
|
32
|
+
return self._last_sample
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def _sample(self) -> int | float | np.ndarray:
|
|
36
|
+
"""Generate a sample from the distribution.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
int | float | np.ndarray: The sampled value(s).
|
|
40
|
+
"""
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def last_sample(self) -> int | float | np.ndarray | None:
|
|
45
|
+
"""Get the last sampled value.
|
|
46
|
+
Returns:
|
|
47
|
+
int | float | np.ndarray | None: The last sampled value, or None if no sample has been taken yet.
|
|
48
|
+
"""
|
|
49
|
+
return self._last_sample
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from humalab.dists.distribution import Distribution
|
|
2
|
+
from typing import Any
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Gaussian(Distribution):
|
|
7
|
+
"""Gaussian (normal) distribution.
|
|
8
|
+
|
|
9
|
+
Samples values from a normal distribution with specified mean (loc) and
|
|
10
|
+
standard deviation (scale). Supports scalar outputs as well as multi-dimensional
|
|
11
|
+
arrays with 1D, 2D, or 3D variants.
|
|
12
|
+
"""
|
|
13
|
+
def __init__(self,
|
|
14
|
+
generator: np.random.Generator,
|
|
15
|
+
loc: float | Any,
|
|
16
|
+
scale: float | Any,
|
|
17
|
+
size: int | tuple[int, ...] | None = None) -> None:
|
|
18
|
+
"""
|
|
19
|
+
Initialize the Gaussian (normal) distribution.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
generator (np.random.Generator): The random number generator.
|
|
23
|
+
loc (float | Any): The mean of the distribution.
|
|
24
|
+
scale (float | Any): The standard deviation of the distribution.
|
|
25
|
+
size (int | tuple[int, ...] | None): The size of the output.
|
|
26
|
+
"""
|
|
27
|
+
super().__init__(generator=generator)
|
|
28
|
+
self._loc = loc
|
|
29
|
+
self._scale = scale
|
|
30
|
+
self._size = size
|
|
31
|
+
|
|
32
|
+
@staticmethod
|
|
33
|
+
def validate(dimensions: int, *args) -> bool:
|
|
34
|
+
"""Validate distribution parameters for the given dimensions.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
dimensions (int): The number of dimensions (0 for scalar, -1 for any).
|
|
38
|
+
*args: The distribution parameters (loc, scale).
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
bool: True if parameters are valid, False otherwise.
|
|
42
|
+
"""
|
|
43
|
+
arg1 = args[0]
|
|
44
|
+
arg2 = args[1]
|
|
45
|
+
if dimensions == 0:
|
|
46
|
+
if not isinstance(arg1, (int, float)):
|
|
47
|
+
return False
|
|
48
|
+
if not isinstance(arg2, (int, float)):
|
|
49
|
+
return False
|
|
50
|
+
return True
|
|
51
|
+
if dimensions == -1:
|
|
52
|
+
return True
|
|
53
|
+
if not isinstance(arg1, (int, float)):
|
|
54
|
+
if isinstance(arg1, (list, np.ndarray)):
|
|
55
|
+
if len(arg1) != dimensions:
|
|
56
|
+
return False
|
|
57
|
+
if not isinstance(arg2, (int, float)):
|
|
58
|
+
if isinstance(arg2, (list, np.ndarray)):
|
|
59
|
+
if len(arg2) != dimensions:
|
|
60
|
+
return False
|
|
61
|
+
return True
|
|
62
|
+
|
|
63
|
+
def _sample(self) -> int | float | np.ndarray:
|
|
64
|
+
"""Generate a sample from the Gaussian distribution.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
int | float | np.ndarray: Sampled value(s) from N(loc, scale).
|
|
68
|
+
"""
|
|
69
|
+
return self._generator.normal(loc=self._loc, scale=self._scale, size=self._size)
|
|
70
|
+
|
|
71
|
+
def __repr__(self) -> str:
|
|
72
|
+
"""String representation of the Gaussian distribution.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
str: String representation showing loc, scale, and size.
|
|
76
|
+
"""
|
|
77
|
+
return f"Gaussian(loc={self._loc}, scale={self._scale}, size={self._size})"
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def create(generator: np.random.Generator,
|
|
81
|
+
loc: float | Any,
|
|
82
|
+
scale: float | Any,
|
|
83
|
+
size: int | tuple[int, ...] | None = None) -> 'Gaussian':
|
|
84
|
+
"""
|
|
85
|
+
Create a Gaussian (normal) distribution.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
generator (np.random.Generator): The random number generator.
|
|
89
|
+
loc (float | Any): The mean of the distribution.
|
|
90
|
+
scale (float | Any): The standard deviation of the distribution.
|
|
91
|
+
size (int | tuple[int, ...] | None): The size of the output.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
Gaussian: The created Gaussian distribution.
|
|
95
|
+
"""
|
|
96
|
+
return Gaussian(generator=generator, loc=loc, scale=scale, size=size)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from humalab.dists.distribution import Distribution
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
class LogUniform(Distribution):
|
|
7
|
+
"""Log-uniform distribution.
|
|
8
|
+
|
|
9
|
+
Samples values uniformly in log-space, useful for hyperparameters that
|
|
10
|
+
span multiple orders of magnitude (e.g., learning rates). The result is
|
|
11
|
+
exp(uniform(log(low), log(high))). Supports scalar outputs as well as
|
|
12
|
+
multi-dimensional arrays with 1D variants.
|
|
13
|
+
"""
|
|
14
|
+
def __init__(self,
|
|
15
|
+
generator: np.random.Generator,
|
|
16
|
+
low: float | Any,
|
|
17
|
+
high: float | Any,
|
|
18
|
+
size: int | tuple[int, ...]| None = None) -> None:
|
|
19
|
+
"""
|
|
20
|
+
Initialize the log-uniform distribution.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
generator (np.random.Generator): The random number generator.
|
|
24
|
+
low (float | Any): The lower bound (inclusive).
|
|
25
|
+
high (float | Any): The upper bound (exclusive).
|
|
26
|
+
size (int | tuple[int, ...]| None): The size of the output.
|
|
27
|
+
"""
|
|
28
|
+
super().__init__(generator=generator)
|
|
29
|
+
self._log_low = np.log(np.array(low))
|
|
30
|
+
self._log_high = np.log(np.array(high))
|
|
31
|
+
self._size = size
|
|
32
|
+
|
|
33
|
+
@staticmethod
|
|
34
|
+
def validate(dimensions: int, *args) -> bool:
|
|
35
|
+
"""Validate distribution parameters for the given dimensions.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
dimensions (int): The number of dimensions (0 for scalar, -1 for any).
|
|
39
|
+
*args: The distribution parameters (low, high).
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
bool: True if parameters are valid, False otherwise.
|
|
43
|
+
"""
|
|
44
|
+
arg1 = args[0]
|
|
45
|
+
arg2 = args[1]
|
|
46
|
+
if dimensions == 0:
|
|
47
|
+
if not isinstance(arg1, (int, float)):
|
|
48
|
+
return False
|
|
49
|
+
if not isinstance(arg2, (int, float)):
|
|
50
|
+
return False
|
|
51
|
+
return True
|
|
52
|
+
if dimensions == -1:
|
|
53
|
+
return True
|
|
54
|
+
if not isinstance(arg1, (int, float)):
|
|
55
|
+
if isinstance(arg1, (list, np.ndarray)):
|
|
56
|
+
if len(arg1) != dimensions:
|
|
57
|
+
return False
|
|
58
|
+
if not isinstance(arg2, (int, float)):
|
|
59
|
+
if isinstance(arg2, (list, np.ndarray)):
|
|
60
|
+
if len(arg2) != dimensions:
|
|
61
|
+
return False
|
|
62
|
+
return True
|
|
63
|
+
|
|
64
|
+
def _sample(self) -> int | float | np.ndarray:
|
|
65
|
+
"""Generate a sample from the log-uniform distribution.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
int | float | np.ndarray: Sampled value(s) in log-space.
|
|
69
|
+
"""
|
|
70
|
+
return np.exp(self._generator.uniform(self._log_low, self._log_high, size=self._size))
|
|
71
|
+
|
|
72
|
+
def __repr__(self) -> str:
|
|
73
|
+
"""String representation of the log-uniform distribution.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
str: String representation showing low, high, and size.
|
|
77
|
+
"""
|
|
78
|
+
return f"LogUniform(low={np.exp(self._log_low)}, high={np.exp(self._log_high)}, size={self._size})"
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def create(generator: np.random.Generator,
|
|
82
|
+
low: float | Any,
|
|
83
|
+
high: float | Any,
|
|
84
|
+
size: int | tuple[int, ...]| None = None) -> 'LogUniform':
|
|
85
|
+
"""
|
|
86
|
+
Create a log-uniform distribution.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
generator (np.random.Generator): The random number generator.
|
|
90
|
+
low (float | Any): The lower bound (inclusive).
|
|
91
|
+
high (float | Any): The upper bound (exclusive).
|
|
92
|
+
size (int | tuple[int, ...]| None): The size of the output.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
LogUniform: The created log-uniform distribution.
|
|
96
|
+
"""
|
|
97
|
+
return LogUniform(generator=generator, low=low, high=high, size=size)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
from humalab.dists.distribution import Distribution
|
|
2
|
+
from typing import Any
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TruncatedGaussian(Distribution):
|
|
7
|
+
"""Truncated Gaussian (normal) distribution.
|
|
8
|
+
|
|
9
|
+
Samples values from a normal distribution with specified mean (loc) and
|
|
10
|
+
standard deviation (scale), but constrained to lie within [low, high].
|
|
11
|
+
Values outside the bounds are resampled until they fall within range.
|
|
12
|
+
Supports scalar outputs as well as multi-dimensional arrays with 1D, 2D, or 3D variants.
|
|
13
|
+
"""
|
|
14
|
+
def __init__(self,
|
|
15
|
+
generator: np.random.Generator,
|
|
16
|
+
loc: float | Any,
|
|
17
|
+
scale: float | Any,
|
|
18
|
+
low: float | Any,
|
|
19
|
+
high: float | Any,
|
|
20
|
+
size: int | tuple[int, ...] | None = None) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Initialize the truncated Gaussian (normal) distribution.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
generator (np.random.Generator): The random number generator.
|
|
26
|
+
loc (float | Any): The mean of the distribution.
|
|
27
|
+
scale (float | Any): The standard deviation of the distribution.
|
|
28
|
+
low (float | Any): The lower truncation bound.
|
|
29
|
+
high (float | Any): The upper truncation bound.
|
|
30
|
+
size (int | tuple[int, ...] | None): The size of the output.
|
|
31
|
+
"""
|
|
32
|
+
super().__init__(generator=generator)
|
|
33
|
+
self._loc = loc
|
|
34
|
+
self._scale = scale
|
|
35
|
+
self._low = low
|
|
36
|
+
self._high = high
|
|
37
|
+
self._size = size
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def validate(dimensions: int, *args) -> bool:
|
|
41
|
+
"""Validate distribution parameters for the given dimensions.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
dimensions (int): The number of dimensions (0 for scalar, -1 for any).
|
|
45
|
+
*args: The distribution parameters (loc, scale, low, high).
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
bool: True if parameters are valid, False otherwise.
|
|
49
|
+
"""
|
|
50
|
+
arg1 = args[0]
|
|
51
|
+
arg2 = args[1]
|
|
52
|
+
arg3 = args[2]
|
|
53
|
+
arg4 = args[3]
|
|
54
|
+
if dimensions == 0:
|
|
55
|
+
if not isinstance(arg1, (int, float)):
|
|
56
|
+
return False
|
|
57
|
+
if not isinstance(arg2, (int, float)):
|
|
58
|
+
return False
|
|
59
|
+
if not isinstance(arg3, (int, float)):
|
|
60
|
+
return False
|
|
61
|
+
if not isinstance(arg4, (int, float)):
|
|
62
|
+
return False
|
|
63
|
+
return True
|
|
64
|
+
if dimensions == -1:
|
|
65
|
+
return True
|
|
66
|
+
if not isinstance(arg1, (int, float)):
|
|
67
|
+
if isinstance(arg1, (list, np.ndarray)):
|
|
68
|
+
if len(arg1) != dimensions:
|
|
69
|
+
return False
|
|
70
|
+
if not isinstance(arg2, (int, float)):
|
|
71
|
+
if isinstance(arg2, (list, np.ndarray)):
|
|
72
|
+
if len(arg2) != dimensions:
|
|
73
|
+
return False
|
|
74
|
+
if not isinstance(arg3, (int, float)):
|
|
75
|
+
if isinstance(arg3, (list, np.ndarray)):
|
|
76
|
+
if len(arg3) != dimensions:
|
|
77
|
+
return False
|
|
78
|
+
if not isinstance(arg4, (int, float)):
|
|
79
|
+
if isinstance(arg4, (list, np.ndarray)):
|
|
80
|
+
if len(arg4) != dimensions:
|
|
81
|
+
return False
|
|
82
|
+
return True
|
|
83
|
+
|
|
84
|
+
def _sample(self) -> int | float | np.ndarray:
|
|
85
|
+
"""Generate a sample from the truncated Gaussian distribution.
|
|
86
|
+
|
|
87
|
+
Samples are generated from N(loc, scale) and resampled if they fall
|
|
88
|
+
outside [low, high].
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
int | float | np.ndarray: Sampled value(s) within [low, high].
|
|
92
|
+
"""
|
|
93
|
+
samples = self._generator.normal(loc=self._loc, scale=self._scale, size=self._size)
|
|
94
|
+
mask = (samples < self._low) | (samples > self._high)
|
|
95
|
+
while np.any(mask):
|
|
96
|
+
samples[mask] = self._generator.normal(loc=self._loc, scale=self._scale, size=np.sum(mask))
|
|
97
|
+
mask = (samples < self._low) | (samples > self._high)
|
|
98
|
+
return samples
|
|
99
|
+
|
|
100
|
+
def __repr__(self) -> str:
|
|
101
|
+
"""String representation of the truncated Gaussian distribution.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
str: String representation showing loc, scale, low, high, and size.
|
|
105
|
+
"""
|
|
106
|
+
return f"TruncatedGaussian(loc={self._loc}, scale={self._scale}, low={self._low}, high={self._high}, size={self._size})"
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def create(generator: np.random.Generator,
|
|
110
|
+
loc: float | Any,
|
|
111
|
+
scale: float | Any,
|
|
112
|
+
low: float | Any,
|
|
113
|
+
high: float | Any,
|
|
114
|
+
size: int | tuple[int, ...] | None = None) -> 'TruncatedGaussian':
|
|
115
|
+
"""
|
|
116
|
+
Create a truncated Gaussian (normal) distribution.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
generator (np.random.Generator): The random number generator.
|
|
120
|
+
loc (float | Any): The mean of the distribution.
|
|
121
|
+
scale (float | Any): The standard deviation of the distribution.
|
|
122
|
+
low (float | Any): The lower truncation bound.
|
|
123
|
+
high (float | Any): The upper truncation bound.
|
|
124
|
+
size (int | tuple[int, ...] | None): The size of the output.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
TruncatedGaussian: The created truncated Gaussian distribution.
|
|
128
|
+
"""
|
|
129
|
+
return TruncatedGaussian(generator=generator, loc=loc, scale=scale, low=low, high=high, size=size)
|
humalab/dists/uniform.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from humalab.dists.distribution import Distribution
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
class Uniform(Distribution):
|
|
7
|
+
"""Uniform distribution over a continuous or discrete range.
|
|
8
|
+
|
|
9
|
+
Samples values uniformly from the half-open interval [low, high). Supports
|
|
10
|
+
scalar outputs as well as multi-dimensional arrays with 1D, 2D, or 3D variants.
|
|
11
|
+
"""
|
|
12
|
+
def __init__(self,
|
|
13
|
+
generator: np.random.Generator,
|
|
14
|
+
low: float | Any,
|
|
15
|
+
high: float | Any,
|
|
16
|
+
size: int | tuple[int, ...] | None = None, ) -> None:
|
|
17
|
+
"""
|
|
18
|
+
Initialize the uniform distribution.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
generator (np.random.Generator): The random number generator.
|
|
22
|
+
low (float | Any): The lower bound (inclusive).
|
|
23
|
+
high (float | Any): The upper bound (exclusive).
|
|
24
|
+
size (int | tuple[int, ...] | None): The size of the output.
|
|
25
|
+
"""
|
|
26
|
+
super().__init__(generator=generator)
|
|
27
|
+
self._low = np.array(low)
|
|
28
|
+
self._high = np.array(high)
|
|
29
|
+
self._size = size
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def validate(dimensions: int, *args) -> bool:
|
|
33
|
+
"""Validate distribution parameters for the given dimensions.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
dimensions (int): The number of dimensions (0 for scalar, -1 for any).
|
|
37
|
+
*args: The distribution parameters (low, high).
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
bool: True if parameters are valid, False otherwise.
|
|
41
|
+
"""
|
|
42
|
+
arg1 = args[0]
|
|
43
|
+
arg2 = args[1]
|
|
44
|
+
if dimensions == 0:
|
|
45
|
+
if not isinstance(arg1, (int, float)):
|
|
46
|
+
return False
|
|
47
|
+
if not isinstance(arg2, (int, float)):
|
|
48
|
+
return False
|
|
49
|
+
return True
|
|
50
|
+
if dimensions == -1:
|
|
51
|
+
return True
|
|
52
|
+
if not isinstance(arg1, (int, float)):
|
|
53
|
+
if isinstance(arg1, (list, np.ndarray)):
|
|
54
|
+
if len(arg1) > dimensions:
|
|
55
|
+
return False
|
|
56
|
+
if not isinstance(arg2, (int, float)):
|
|
57
|
+
if isinstance(arg2, (list, np.ndarray)):
|
|
58
|
+
if len(arg2) > dimensions:
|
|
59
|
+
return False
|
|
60
|
+
return True
|
|
61
|
+
|
|
62
|
+
def _sample(self) -> int | float | np.ndarray:
|
|
63
|
+
"""Generate a sample from the uniform distribution.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
int | float | np.ndarray: Sampled value(s) from [low, high).
|
|
67
|
+
"""
|
|
68
|
+
return self._generator.uniform(self._low, self._high, size=self._size)
|
|
69
|
+
|
|
70
|
+
def __repr__(self) -> str:
|
|
71
|
+
"""String representation of the uniform distribution.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
str: String representation showing low, high, and size.
|
|
75
|
+
"""
|
|
76
|
+
return f"Uniform(low={self._low}, high={self._high}, size={self._size})"
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def create(generator: np.random.Generator,
|
|
80
|
+
low: float | Any,
|
|
81
|
+
high: float | Any,
|
|
82
|
+
size: int | tuple[int, ...] | None = None) -> 'Uniform':
|
|
83
|
+
"""
|
|
84
|
+
Create a uniform distribution.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
generator (np.random.Generator): The random number generator.
|
|
88
|
+
low (float | Any): The lower bound (inclusive).
|
|
89
|
+
high (float | Any): The upper bound (exclusive).
|
|
90
|
+
size (int | tuple[int, ...] | None): The size of the output.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Uniform: The created uniform distribution.
|
|
94
|
+
"""
|
|
95
|
+
return Uniform(generator=generator, low=low, high=high, size=size)
|