hypergrid 0.0.1a1__tar.gz
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.
- hypergrid-0.0.1a1/LICENSE +21 -0
- hypergrid-0.0.1a1/PKG-INFO +25 -0
- hypergrid-0.0.1a1/README.md +5 -0
- hypergrid-0.0.1a1/pyproject.toml +68 -0
- hypergrid-0.0.1a1/setup.cfg +4 -0
- hypergrid-0.0.1a1/src/hypergrid/__init__.py +0 -0
- hypergrid-0.0.1a1/src/hypergrid/grid.py +211 -0
- hypergrid-0.0.1a1/src/hypergrid/py.typed +0 -0
- hypergrid-0.0.1a1/src/hypergrid.egg-info/PKG-INFO +25 -0
- hypergrid-0.0.1a1/src/hypergrid.egg-info/SOURCES.txt +11 -0
- hypergrid-0.0.1a1/src/hypergrid.egg-info/dependency_links.txt +1 -0
- hypergrid-0.0.1a1/src/hypergrid.egg-info/not-zip-safe +1 -0
- hypergrid-0.0.1a1/src/hypergrid.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 justin-yan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: hypergrid
|
|
3
|
+
Version: 0.0.1a1
|
|
4
|
+
Summary: Hypergrid is a Python package for the concise declaration and manipulation of parameter grids, making hyperparameter optimization and batch job dispatch more manageable.
|
|
5
|
+
Author-email: Justin Yan <justin@iomorphic.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/justin-yan/hypergrid
|
|
7
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Requires-Python: >=3.8
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
|
|
21
|
+
# hypergrid
|
|
22
|
+
|
|
23
|
+
Hypergrid is designed to enable concise declaration and manipulation of parameter grids possible, which are often required when tuning ML hyperparameters or defining large batch jobs.
|
|
24
|
+
|
|
25
|
+
Hypergrid allows you to easily define multi-dimensional parameter grids, and then combine them in various ways, including sum-types, product-types, and co-iteration. Once defined, you can easily map, filter, select, and apply arbitrary functions in order to easily compose and iterate over your grid.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# hypergrid
|
|
2
|
+
|
|
3
|
+
Hypergrid is designed to enable concise declaration and manipulation of parameter grids possible, which are often required when tuning ML hyperparameters or defining large batch jobs.
|
|
4
|
+
|
|
5
|
+
Hypergrid allows you to easily define multi-dimensional parameter grids, and then combine them in various ways, including sum-types, product-types, and co-iteration. Once defined, you can easily map, filter, select, and apply arbitrary functions in order to easily compose and iterate over your grid.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hypergrid"
|
|
7
|
+
version = "0.0.1a1"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Justin Yan", email="justin@iomorphic.com" }
|
|
10
|
+
]
|
|
11
|
+
description = "Hypergrid is a Python package for the concise declaration and manipulation of parameter grids, making hyperparameter optimization and batch job dispatch more manageable."
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.8"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Programming Language :: Python",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.8",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
"Homepage" = "https://github.com/justin-yan/hypergrid"
|
|
31
|
+
|
|
32
|
+
[tool.setuptools]
|
|
33
|
+
zip-safe = false
|
|
34
|
+
include-package-data = true
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.package-data]
|
|
37
|
+
"hypergrid" = ["py.typed"]
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.packages.find]
|
|
40
|
+
where = ["src"]
|
|
41
|
+
|
|
42
|
+
#######
|
|
43
|
+
### Miscellaneous Tool Configuration
|
|
44
|
+
#######
|
|
45
|
+
[tool.black]
|
|
46
|
+
line-length = 150
|
|
47
|
+
skip-string-normalization = true
|
|
48
|
+
target-version = ['py311']
|
|
49
|
+
include = '\.pyi?$'
|
|
50
|
+
|
|
51
|
+
[tool.ruff]
|
|
52
|
+
select = ["E", "F"]
|
|
53
|
+
line-length = 150
|
|
54
|
+
target-version = "py311"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
[tool.pytest.ini_options]
|
|
58
|
+
addopts = "-ra -q"
|
|
59
|
+
|
|
60
|
+
[tool.mypy]
|
|
61
|
+
mypy_path = "src"
|
|
62
|
+
disallow_untyped_defs = true
|
|
63
|
+
disallow_any_unimported = true
|
|
64
|
+
no_implicit_optional = true
|
|
65
|
+
check_untyped_defs = true
|
|
66
|
+
warn_return_any = true
|
|
67
|
+
show_error_codes = true
|
|
68
|
+
warn_unused_ignores = true
|
|
File without changes
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import itertools
|
|
4
|
+
from collections import OrderedDict, namedtuple
|
|
5
|
+
from typing import Any, Callable, List, Protocol
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class IGrid(Protocol):
|
|
9
|
+
def __repr__(self) -> str:
|
|
10
|
+
...
|
|
11
|
+
|
|
12
|
+
def __str__(self) -> str:
|
|
13
|
+
...
|
|
14
|
+
|
|
15
|
+
def __iter__(self) -> Any:
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
def __add__(self, other: IGrid) -> SumGrid:
|
|
19
|
+
return SumGrid(self, other)
|
|
20
|
+
|
|
21
|
+
def __mul__(self, other: IGrid) -> ProductGrid:
|
|
22
|
+
return ProductGrid(self, other)
|
|
23
|
+
|
|
24
|
+
def __and__(self, other: IGrid) -> CoGrid:
|
|
25
|
+
return CoGrid(self, other)
|
|
26
|
+
|
|
27
|
+
def apply(self, **kwargs: Callable[[Any], Any]) -> IGrid:
|
|
28
|
+
# TODO: what should we do if no lambda is provided?
|
|
29
|
+
# TODO: what should the expected signature of the lambda be? Should we unpack the namedtuple or receive a namedtuple instead?
|
|
30
|
+
applied_grids = []
|
|
31
|
+
|
|
32
|
+
for dim_name, transform in kwargs.items():
|
|
33
|
+
transformed_elements = [transform(grid_element) for grid_element in self]
|
|
34
|
+
new_grid = Grid(**{dim_name: transformed_elements})
|
|
35
|
+
applied_grids.append(new_grid)
|
|
36
|
+
|
|
37
|
+
final_co_grid: IGrid = applied_grids[0]
|
|
38
|
+
for grid in applied_grids[1:]:
|
|
39
|
+
final_co_grid = CoGrid(final_co_grid, grid)
|
|
40
|
+
|
|
41
|
+
return final_co_grid
|
|
42
|
+
|
|
43
|
+
def select(self, *dim_names: str) -> IGrid:
|
|
44
|
+
# TODO: what do we do if no dimnames are provided?
|
|
45
|
+
selected_elements: dict = {dim_name: [] for dim_name in dim_names}
|
|
46
|
+
|
|
47
|
+
for grid_element in self:
|
|
48
|
+
for dim_name in dim_names:
|
|
49
|
+
# TODO: How do we want to handle the case when a value isn't present?
|
|
50
|
+
selected_value = getattr(grid_element, dim_name)
|
|
51
|
+
selected_elements[dim_name].append(selected_value)
|
|
52
|
+
|
|
53
|
+
selected_grids = [Grid(**{dim_name: values}) for dim_name, values in selected_elements.items()]
|
|
54
|
+
|
|
55
|
+
final_co_grid: IGrid = selected_grids[0]
|
|
56
|
+
for grid in selected_grids[1:]:
|
|
57
|
+
final_co_grid = CoGrid(final_co_grid, grid)
|
|
58
|
+
|
|
59
|
+
return final_co_grid
|
|
60
|
+
|
|
61
|
+
def map(self, **kwargs: Callable[[Any], Any]) -> MapGrid:
|
|
62
|
+
return MapGrid(self, **kwargs)
|
|
63
|
+
|
|
64
|
+
def filter(self, predicate: Callable[[Any], bool]) -> FilterGrid:
|
|
65
|
+
return FilterGrid(self, predicate)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class SumGrid(IGrid):
|
|
69
|
+
def __init__(self, grid1: IGrid, grid2: IGrid) -> None:
|
|
70
|
+
self.grid1 = grid1
|
|
71
|
+
self.grid2 = grid2
|
|
72
|
+
|
|
73
|
+
def __repr__(self) -> str:
|
|
74
|
+
return f"SumGrid({repr(self.grid1)}, {repr(self.grid2)})"
|
|
75
|
+
|
|
76
|
+
def __str__(self) -> str:
|
|
77
|
+
return f"SumGrid({str(self.grid1)}, {str(self.grid2)})"
|
|
78
|
+
|
|
79
|
+
def __iter__(self) -> Any:
|
|
80
|
+
for grid_element in itertools.chain(self.grid1, self.grid2):
|
|
81
|
+
yield grid_element
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class ProductGrid(IGrid):
|
|
85
|
+
# TODO: Make product grids fail if subdimensions collide? How does this work with things like maps, etc.?
|
|
86
|
+
def __init__(self, grid1: IGrid, grid2: IGrid) -> None:
|
|
87
|
+
self.grid1 = grid1
|
|
88
|
+
self.grid2 = grid2
|
|
89
|
+
self.namedtuple_cache: dict = {}
|
|
90
|
+
|
|
91
|
+
def __repr__(self) -> str:
|
|
92
|
+
return f"ProductGrid({repr(self.grid1)}, {repr(self.grid2)})"
|
|
93
|
+
|
|
94
|
+
def __str__(self) -> str:
|
|
95
|
+
return f"ProductGrid({str(self.grid1)}, {str(self.grid2)})"
|
|
96
|
+
|
|
97
|
+
def __iter__(self) -> Any:
|
|
98
|
+
# TODO: is there a way to do this without accessing private attributes?
|
|
99
|
+
for grid_element1, grid_element2 in itertools.product(self.grid1, self.grid2):
|
|
100
|
+
field_names1 = grid_element1._fields
|
|
101
|
+
field_names2 = grid_element2._fields
|
|
102
|
+
concatenated_field_names = list(field_names1) + list(field_names2)
|
|
103
|
+
field_names_key = tuple(concatenated_field_names)
|
|
104
|
+
|
|
105
|
+
if field_names_key not in self.namedtuple_cache:
|
|
106
|
+
self.namedtuple_cache[field_names_key] = namedtuple("GridElement", concatenated_field_names)
|
|
107
|
+
|
|
108
|
+
concatenated_namedtuple_class = self.namedtuple_cache[field_names_key]
|
|
109
|
+
concatenated_element = concatenated_namedtuple_class(*(grid_element1 + grid_element2))
|
|
110
|
+
yield concatenated_element
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class Grid(IGrid):
|
|
114
|
+
dimensions: OrderedDict[str, List[Any]]
|
|
115
|
+
|
|
116
|
+
def __init__(self, **kwargs: List[Any]) -> None:
|
|
117
|
+
self.dimensions = OrderedDict()
|
|
118
|
+
for dim, values in kwargs.items():
|
|
119
|
+
self.dimensions[dim] = values
|
|
120
|
+
|
|
121
|
+
def __repr__(self) -> str:
|
|
122
|
+
dim_str = ", ".join([f"{dim}={values}" for dim, values in self.dimensions.items()])
|
|
123
|
+
return f"Grid({dim_str})"
|
|
124
|
+
|
|
125
|
+
def __str__(self) -> str:
|
|
126
|
+
return self.__repr__()
|
|
127
|
+
|
|
128
|
+
def __iter__(self) -> Any:
|
|
129
|
+
fieldnames: tuple = tuple(self.dimensions.keys())
|
|
130
|
+
namedtuple_class = namedtuple("GridElement", fieldnames) # type: ignore
|
|
131
|
+
for element_tuple in itertools.product(*self.dimensions.values()):
|
|
132
|
+
yield namedtuple_class(*element_tuple)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class GridShapeMismatchError(Exception):
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class CoGrid(IGrid):
|
|
140
|
+
def __init__(self, grid1: IGrid, grid2: IGrid) -> None:
|
|
141
|
+
if len(list(grid1)) == len(list(grid2)):
|
|
142
|
+
self.grid1 = grid1
|
|
143
|
+
self.grid2 = grid2
|
|
144
|
+
self.namedtuple_cache: dict = {}
|
|
145
|
+
else:
|
|
146
|
+
raise GridShapeMismatchError("The shapes of the input grids must be the same")
|
|
147
|
+
|
|
148
|
+
def __repr__(self) -> str:
|
|
149
|
+
return f"CoGrid({repr(self.grid1)}, {repr(self.grid2)})"
|
|
150
|
+
|
|
151
|
+
def __str__(self) -> str:
|
|
152
|
+
return f"CoGrid({str(self.grid1)}, {str(self.grid2)})"
|
|
153
|
+
|
|
154
|
+
def __iter__(self) -> Any:
|
|
155
|
+
for grid_element1, grid_element2 in zip(self.grid1, self.grid2):
|
|
156
|
+
field_names1 = grid_element1._fields
|
|
157
|
+
field_names2 = grid_element2._fields
|
|
158
|
+
concatenated_field_names = list(field_names1) + list(field_names2)
|
|
159
|
+
field_names_key = tuple(concatenated_field_names)
|
|
160
|
+
|
|
161
|
+
if field_names_key not in self.namedtuple_cache:
|
|
162
|
+
self.namedtuple_cache[field_names_key] = namedtuple("GridElement", concatenated_field_names)
|
|
163
|
+
|
|
164
|
+
concatenated_namedtuple_class = self.namedtuple_cache[field_names_key]
|
|
165
|
+
concatenated_element = concatenated_namedtuple_class(*(grid_element1 + grid_element2))
|
|
166
|
+
yield concatenated_element
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class MapGrid(IGrid):
|
|
170
|
+
def __init__(self, grid: IGrid, **kwargs: Callable[[Any], Any]) -> None:
|
|
171
|
+
self.grid = grid
|
|
172
|
+
self.dimension_mapping = kwargs
|
|
173
|
+
self.namedtuple_cache: dict = {}
|
|
174
|
+
|
|
175
|
+
def __repr__(self) -> str:
|
|
176
|
+
mappings_str = ", ".join([f"{dim_name}={func.__name__}" for dim_name, func in self.dimension_mapping.items()])
|
|
177
|
+
return f"MapGrid({repr(self.grid)}, {mappings_str})"
|
|
178
|
+
|
|
179
|
+
def __str__(self) -> str:
|
|
180
|
+
return f"MapGrid({str(self.grid)}, {', '.join(self.dimension_mapping.keys())})"
|
|
181
|
+
|
|
182
|
+
def __iter__(self) -> Any:
|
|
183
|
+
for grid_element in self.grid:
|
|
184
|
+
new_values = {dim_name: func(grid_element) for dim_name, func in self.dimension_mapping.items()}
|
|
185
|
+
concatenated_values = tuple(grid_element) + tuple(new_values.values())
|
|
186
|
+
field_names = grid_element._fields + tuple(new_values.keys())
|
|
187
|
+
|
|
188
|
+
field_names_key = tuple(field_names)
|
|
189
|
+
if field_names_key not in self.namedtuple_cache:
|
|
190
|
+
self.namedtuple_cache[field_names_key] = namedtuple("GridElement", field_names)
|
|
191
|
+
|
|
192
|
+
concatenated_namedtuple_class = self.namedtuple_cache[field_names_key]
|
|
193
|
+
concatenated_element = concatenated_namedtuple_class(*concatenated_values)
|
|
194
|
+
yield concatenated_element
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class FilterGrid(IGrid):
|
|
198
|
+
def __init__(self, grid: IGrid, predicate: Callable[[Any], bool]) -> None:
|
|
199
|
+
self.grid = grid
|
|
200
|
+
self.predicate = predicate
|
|
201
|
+
|
|
202
|
+
def __repr__(self) -> str:
|
|
203
|
+
return f"FilterGrid({repr(self.grid)}, {self.predicate.__name__})"
|
|
204
|
+
|
|
205
|
+
def __str__(self) -> str:
|
|
206
|
+
return f"FilterGrid({str(self.grid)}, {self.predicate.__name__})"
|
|
207
|
+
|
|
208
|
+
def __iter__(self) -> Any:
|
|
209
|
+
for grid_element in self.grid:
|
|
210
|
+
if self.predicate(grid_element):
|
|
211
|
+
yield grid_element
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: hypergrid
|
|
3
|
+
Version: 0.0.1a1
|
|
4
|
+
Summary: Hypergrid is a Python package for the concise declaration and manipulation of parameter grids, making hyperparameter optimization and batch job dispatch more manageable.
|
|
5
|
+
Author-email: Justin Yan <justin@iomorphic.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/justin-yan/hypergrid
|
|
7
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Requires-Python: >=3.8
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
|
|
21
|
+
# hypergrid
|
|
22
|
+
|
|
23
|
+
Hypergrid is designed to enable concise declaration and manipulation of parameter grids possible, which are often required when tuning ML hyperparameters or defining large batch jobs.
|
|
24
|
+
|
|
25
|
+
Hypergrid allows you to easily define multi-dimensional parameter grids, and then combine them in various ways, including sum-types, product-types, and co-iteration. Once defined, you can easily map, filter, select, and apply arbitrary functions in order to easily compose and iterate over your grid.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/hypergrid/__init__.py
|
|
5
|
+
src/hypergrid/grid.py
|
|
6
|
+
src/hypergrid/py.typed
|
|
7
|
+
src/hypergrid.egg-info/PKG-INFO
|
|
8
|
+
src/hypergrid.egg-info/SOURCES.txt
|
|
9
|
+
src/hypergrid.egg-info/dependency_links.txt
|
|
10
|
+
src/hypergrid.egg-info/not-zip-safe
|
|
11
|
+
src/hypergrid.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
hypergrid
|