pyglove 0.4.5.dev202501050808__py3-none-any.whl → 0.4.5.dev202501060809__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.
- pyglove/core/__init__.py +24 -21
- pyglove/core/geno/base.py +53 -38
- pyglove/core/geno/base_test.py +2 -4
- pyglove/core/geno/categorical.py +36 -27
- pyglove/core/geno/custom.py +18 -15
- pyglove/core/geno/numerical.py +19 -16
- pyglove/core/geno/space.py +3 -4
- pyglove/core/hyper/base.py +6 -6
- pyglove/core/hyper/categorical.py +91 -52
- pyglove/core/hyper/custom.py +7 -7
- pyglove/core/hyper/custom_test.py +9 -10
- pyglove/core/hyper/derived.py +30 -22
- pyglove/core/hyper/derived_test.py +2 -4
- pyglove/core/hyper/dynamic_evaluation.py +3 -4
- pyglove/core/hyper/evolvable.py +57 -46
- pyglove/core/hyper/numerical.py +48 -24
- pyglove/core/hyper/numerical_test.py +9 -9
- pyglove/core/hyper/object_template.py +58 -46
- pyglove/core/logging_test.py +0 -2
- pyglove/core/patching/object_factory.py +4 -4
- pyglove/core/patching/pattern_based.py +4 -4
- pyglove/core/patching/rule_based.py +4 -3
- pyglove/core/symbolic/base.py +167 -131
- pyglove/core/symbolic/base_test.py +17 -19
- pyglove/core/symbolic/boilerplate.py +4 -5
- pyglove/core/symbolic/class_wrapper.py +9 -9
- pyglove/core/symbolic/compounding.py +2 -2
- pyglove/core/symbolic/compounding_test.py +2 -4
- pyglove/core/symbolic/dict.py +70 -54
- pyglove/core/symbolic/dict_test.py +117 -100
- pyglove/core/symbolic/diff.py +12 -12
- pyglove/core/symbolic/flags.py +1 -1
- pyglove/core/symbolic/functor.py +16 -15
- pyglove/core/symbolic/functor_test.py +2 -4
- pyglove/core/symbolic/inferred.py +2 -2
- pyglove/core/symbolic/list.py +70 -47
- pyglove/core/symbolic/list_test.py +117 -98
- pyglove/core/symbolic/object.py +42 -40
- pyglove/core/symbolic/object_test.py +95 -88
- pyglove/core/symbolic/origin.py +5 -7
- pyglove/core/symbolic/pure_symbolic.py +4 -3
- pyglove/core/symbolic/ref.py +12 -8
- pyglove/core/tuning/local_backend.py +2 -2
- pyglove/core/tuning/protocols.py +3 -3
- pyglove/core/typing/annotation_conversion.py +3 -3
- pyglove/core/typing/callable_ext.py +11 -13
- pyglove/core/typing/callable_signature.py +19 -18
- pyglove/core/typing/callable_signature_test.py +3 -5
- pyglove/core/typing/class_schema.py +48 -44
- pyglove/core/typing/class_schema_test.py +3 -5
- pyglove/core/typing/custom_typing.py +5 -4
- pyglove/core/typing/key_specs.py +5 -7
- pyglove/core/typing/key_specs_test.py +4 -4
- pyglove/core/typing/type_conversion.py +4 -5
- pyglove/core/typing/type_conversion_test.py +12 -12
- pyglove/core/typing/typed_missing.py +6 -7
- pyglove/core/typing/typed_missing_test.py +7 -8
- pyglove/core/typing/value_specs.py +210 -141
- pyglove/core/typing/value_specs_test.py +12 -13
- pyglove/core/utils/__init__.py +159 -0
- pyglove/core/{object_utils → utils}/common_traits_test.py +1 -3
- pyglove/core/{object_utils → utils}/docstr_utils_test.py +1 -3
- pyglove/core/{object_utils → utils}/error_utils.py +3 -3
- pyglove/core/{object_utils → utils}/error_utils_test.py +1 -1
- pyglove/core/{object_utils → utils}/formatting.py +1 -1
- pyglove/core/{object_utils → utils}/formatting_test.py +1 -2
- pyglove/core/{object_utils → utils}/hierarchical.py +23 -25
- pyglove/core/{object_utils → utils}/hierarchical_test.py +3 -5
- pyglove/core/{object_utils → utils}/json_conversion_test.py +1 -3
- pyglove/core/{object_utils → utils}/missing.py +2 -2
- pyglove/core/{object_utils → utils}/missing_test.py +2 -4
- pyglove/core/{object_utils → utils}/thread_local_test.py +1 -3
- pyglove/core/{object_utils → utils}/timing.py +3 -3
- pyglove/core/{object_utils → utils}/timing_test.py +2 -3
- pyglove/core/{object_utils → utils}/value_location.py +2 -2
- pyglove/core/{object_utils → utils}/value_location_test.py +2 -4
- pyglove/core/views/base.py +25 -29
- pyglove/core/views/html/base.py +14 -15
- pyglove/core/views/html/controls/base.py +5 -5
- pyglove/core/views/html/controls/progress_bar.py +3 -5
- pyglove/core/views/html/tree_view.py +37 -35
- {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/METADATA +1 -1
- {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/RECORD +90 -90
- {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/WHEEL +1 -1
- pyglove/core/object_utils/__init__.py +0 -161
- /pyglove/core/{object_utils → utils}/common_traits.py +0 -0
- /pyglove/core/{object_utils → utils}/docstr_utils.py +0 -0
- /pyglove/core/{object_utils → utils}/json_conversion.py +0 -0
- /pyglove/core/{object_utils → utils}/thread_local.py +0 -0
- {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/LICENSE +0 -0
- {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/top_level.txt +0 -0
pyglove/core/__init__.py
CHANGED
@@ -37,8 +37,7 @@ Here lists the sub-modules included in the core PyGlove library:
|
|
37
37
|
|__ tuning : Interface for program tuning with a local backend.
|
38
38
|
|__ detouring : Detouring classes creation without symbolic types.
|
39
39
|
|__ patching : Patching a program with URL-like strings.
|
40
|
-
|__
|
41
|
-
|
40
|
+
|__ utils : Utility libary on operating with Python objects.
|
42
41
|
"""
|
43
42
|
|
44
43
|
# NOTE(daiyip): We disable bad-import-order to preserve the relation of
|
@@ -273,31 +272,35 @@ ObjectFactory = patching.ObjectFactory
|
|
273
272
|
|
274
273
|
|
275
274
|
#
|
276
|
-
# Symbols from '
|
275
|
+
# Symbols from 'utils' sub-module.
|
277
276
|
#
|
278
277
|
|
279
|
-
from pyglove.core import
|
280
|
-
|
281
|
-
|
282
|
-
|
278
|
+
from pyglove.core import utils
|
279
|
+
|
280
|
+
# For backward compatibility.
|
281
|
+
object_utils = utils
|
282
|
+
|
283
|
+
KeyPath = utils.KeyPath
|
284
|
+
KeyPathSet = utils.KeyPathSet
|
285
|
+
MISSING_VALUE = utils.MISSING_VALUE
|
283
286
|
|
284
|
-
Formattable =
|
285
|
-
repr_format =
|
286
|
-
str_format =
|
287
|
+
Formattable = utils.Formattable
|
288
|
+
repr_format = utils.repr_format
|
289
|
+
str_format = utils.str_format
|
287
290
|
|
288
|
-
MaybePartial =
|
289
|
-
JSONConvertible =
|
290
|
-
DocStr =
|
291
|
+
MaybePartial = utils.MaybePartial
|
292
|
+
JSONConvertible = utils.JSONConvertible
|
293
|
+
DocStr = utils.DocStr
|
291
294
|
|
292
|
-
registered_types =
|
293
|
-
explicit_method_override =
|
295
|
+
registered_types = utils.registered_types
|
296
|
+
explicit_method_override = utils.explicit_method_override
|
294
297
|
|
295
|
-
is_partial =
|
296
|
-
format =
|
297
|
-
print =
|
298
|
-
docstr =
|
299
|
-
catch_errors =
|
300
|
-
timeit =
|
298
|
+
is_partial = utils.is_partial
|
299
|
+
format = utils.format # pylint: disable=redefined-builtin
|
300
|
+
print = utils.print # pylint: disable=redefined-builtin
|
301
|
+
docstr = utils.docstr
|
302
|
+
catch_errors = utils.catch_errors
|
303
|
+
timeit = utils.timeit
|
301
304
|
|
302
305
|
# Symbols from 'views' sub-module.
|
303
306
|
|
pyglove/core/geno/base.py
CHANGED
@@ -19,9 +19,9 @@ import random
|
|
19
19
|
import types
|
20
20
|
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
21
21
|
|
22
|
-
from pyglove.core import object_utils
|
23
22
|
from pyglove.core import symbolic
|
24
23
|
from pyglove.core import typing as pg_typing
|
24
|
+
from pyglove.core import utils
|
25
25
|
|
26
26
|
|
27
27
|
class AttributeDict(dict):
|
@@ -37,12 +37,20 @@ class AttributeDict(dict):
|
|
37
37
|
|
38
38
|
|
39
39
|
@symbolic.members([
|
40
|
-
(
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
40
|
+
(
|
41
|
+
'location',
|
42
|
+
pg_typing.Object(utils.KeyPath, default=utils.KeyPath()),
|
43
|
+
(
|
44
|
+
'KeyPath of associated genetic encoder relative to parent object'
|
45
|
+
' template. This allows DNA generator to apply rule based on'
|
46
|
+
' locations.'
|
47
|
+
),
|
48
|
+
),
|
49
|
+
(
|
50
|
+
'hints',
|
51
|
+
pg_typing.Any(default=None),
|
52
|
+
'Hints for DNA generator to consume.',
|
53
|
+
),
|
46
54
|
])
|
47
55
|
class DNASpec(symbolic.Object):
|
48
56
|
"""Base class for DNA specifications (genotypes).
|
@@ -175,7 +183,7 @@ class DNASpec(symbolic.Object):
|
|
175
183
|
"""Returns all decision points in their declaration order."""
|
176
184
|
|
177
185
|
@property
|
178
|
-
def decision_ids(self) -> List[
|
186
|
+
def decision_ids(self) -> List[utils.KeyPath]:
|
179
187
|
"""Returns decision IDs."""
|
180
188
|
return list(self._decision_point_by_id.keys())
|
181
189
|
|
@@ -286,7 +294,7 @@ class DNASpec(symbolic.Object):
|
|
286
294
|
return self.parent_spec if self.is_space else self.parent_spec.parent_choice
|
287
295
|
|
288
296
|
@property
|
289
|
-
def id(self) ->
|
297
|
+
def id(self) -> utils.KeyPath:
|
290
298
|
"""Returns a path of locations from the root as the ID for current node."""
|
291
299
|
if self._id is None:
|
292
300
|
parent = self.parent_spec
|
@@ -295,18 +303,20 @@ class DNASpec(symbolic.Object):
|
|
295
303
|
elif self.is_space:
|
296
304
|
assert parent.is_categorical, parent
|
297
305
|
assert self.index is not None
|
298
|
-
self._id =
|
299
|
-
|
300
|
-
|
306
|
+
self._id = (
|
307
|
+
utils.KeyPath(
|
308
|
+
ConditionalKey(self.index, len(parent.candidates)), parent.id
|
309
|
+
)
|
310
|
+
+ self.location
|
311
|
+
)
|
301
312
|
else:
|
302
313
|
# Float() or a multi-choice spec of a parent Choice.
|
303
314
|
self._id = parent.id + self.location
|
304
315
|
return self._id
|
305
316
|
|
306
|
-
def get(
|
307
|
-
|
308
|
-
|
309
|
-
) -> Union['DecisionPoint', List['DecisionPoint']]:
|
317
|
+
def get(
|
318
|
+
self, name_or_id: Union[utils.KeyPath, str], default: Any = None
|
319
|
+
) -> Union['DecisionPoint', List['DecisionPoint']]:
|
310
320
|
"""Get decision point(s) by name or ID."""
|
311
321
|
try:
|
312
322
|
return self[name_or_id]
|
@@ -314,9 +324,8 @@ class DNASpec(symbolic.Object):
|
|
314
324
|
return default
|
315
325
|
|
316
326
|
def __getitem__(
|
317
|
-
self,
|
318
|
-
|
319
|
-
) -> Union['DecisionPoint', List['DecisionPoint']]:
|
327
|
+
self, name_or_id: Union[utils.KeyPath, str]
|
328
|
+
) -> Union['DecisionPoint', List['DecisionPoint']]:
|
320
329
|
"""Get decision point(s) by name or ID ."""
|
321
330
|
v = self._named_decision_points.get(name_or_id, None)
|
322
331
|
if v is None:
|
@@ -475,7 +484,7 @@ class DNA(symbolic.Object):
|
|
475
484
|
# Allow assignment on symbolic attributes.
|
476
485
|
allow_symbolic_assignment = True
|
477
486
|
|
478
|
-
@
|
487
|
+
@utils.explicit_method_override
|
479
488
|
def __init__(
|
480
489
|
self,
|
481
490
|
value: Union[None, int, float, str, List[Any], Tuple[Any]] = None,
|
@@ -727,7 +736,7 @@ class DNA(symbolic.Object):
|
|
727
736
|
return self._decision_by_id_cache
|
728
737
|
|
729
738
|
@property
|
730
|
-
def decision_ids(self) -> List[
|
739
|
+
def decision_ids(self) -> List[utils.KeyPath]:
|
731
740
|
"""Returns decision IDs."""
|
732
741
|
self._ensure_dna_spec()
|
733
742
|
return self._spec.decision_ids
|
@@ -1249,9 +1258,11 @@ class DNA(symbolic.Object):
|
|
1249
1258
|
return dna
|
1250
1259
|
|
1251
1260
|
def to_numbers(
|
1252
|
-
self,
|
1253
|
-
|
1254
|
-
|
1261
|
+
self,
|
1262
|
+
flatten: bool = True,
|
1263
|
+
) -> Union[
|
1264
|
+
List[Union[int, float, str]], utils.Nestable[Union[int, float, str]]
|
1265
|
+
]:
|
1255
1266
|
"""Returns a (maybe) nested structure of numbers as decisions.
|
1256
1267
|
|
1257
1268
|
Args:
|
@@ -1338,7 +1349,7 @@ class DNA(symbolic.Object):
|
|
1338
1349
|
f'Location: {dna_spec.location.path}.')
|
1339
1350
|
children = []
|
1340
1351
|
for i, choice in enumerate(decision):
|
1341
|
-
choice_location =
|
1352
|
+
choice_location = utils.KeyPath(i, dna_spec.location)
|
1342
1353
|
if not isinstance(choice, int):
|
1343
1354
|
raise ValueError(
|
1344
1355
|
f'Choice value should be int. Encountered: {choice}, '
|
@@ -1410,7 +1421,7 @@ class DNA(symbolic.Object):
|
|
1410
1421
|
|
1411
1422
|
if type_info:
|
1412
1423
|
json_value = {
|
1413
|
-
|
1424
|
+
utils.JSONConvertible.TYPE_NAME_KEY: (
|
1414
1425
|
self.__class__.__serialization_key__
|
1415
1426
|
),
|
1416
1427
|
'format': 'compact',
|
@@ -1435,7 +1446,8 @@ class DNA(symbolic.Object):
|
|
1435
1446
|
json_value: Dict[str, Any],
|
1436
1447
|
*,
|
1437
1448
|
allow_partial: bool = False,
|
1438
|
-
root_path: Optional[
|
1449
|
+
root_path: Optional[utils.KeyPath] = None,
|
1450
|
+
) -> 'DNA':
|
1439
1451
|
"""Class method that load a DNA from a JSON value.
|
1440
1452
|
|
1441
1453
|
Args:
|
@@ -1472,8 +1484,8 @@ class DNA(symbolic.Object):
|
|
1472
1484
|
return not self.children
|
1473
1485
|
|
1474
1486
|
def __getitem__(
|
1475
|
-
self, key: Union[int, slice, str,
|
1476
|
-
|
1487
|
+
self, key: Union[int, slice, str, utils.KeyPath, 'DecisionPoint']
|
1488
|
+
) -> Union[None, 'DNA', List[Optional['DNA']]]:
|
1477
1489
|
"""Get an immediate child DNA or DNA in the sub-tree.
|
1478
1490
|
|
1479
1491
|
Args:
|
@@ -1504,10 +1516,11 @@ class DNA(symbolic.Object):
|
|
1504
1516
|
v = self._decision_by_id[key]
|
1505
1517
|
return v
|
1506
1518
|
|
1507
|
-
def get(
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1519
|
+
def get(
|
1520
|
+
self,
|
1521
|
+
key: Union[int, slice, str, utils.KeyPath, 'DecisionPoint'],
|
1522
|
+
default: Any = None,
|
1523
|
+
) -> Union[Any, None, 'DNA', List[Optional['DNA']]]:
|
1511
1524
|
"""Get an immediate child DNA or DNA in the sub-tree."""
|
1512
1525
|
try:
|
1513
1526
|
return self[key]
|
@@ -1529,8 +1542,9 @@ class DNA(symbolic.Object):
|
|
1529
1542
|
return True
|
1530
1543
|
else:
|
1531
1544
|
raise ValueError(
|
1532
|
-
|
1533
|
-
f'{
|
1545
|
+
'DNA.__contains__ does not accept '
|
1546
|
+
f'{utils.quote_if_str(dna_or_value)!r}.'
|
1547
|
+
)
|
1534
1548
|
return False
|
1535
1549
|
|
1536
1550
|
def __hash__(self):
|
@@ -1605,12 +1619,13 @@ class DNA(symbolic.Object):
|
|
1605
1619
|
):
|
1606
1620
|
"""Customize format method for DNA for more compact representation."""
|
1607
1621
|
if as_dict and self.spec:
|
1608
|
-
details =
|
1622
|
+
details = utils.format(
|
1609
1623
|
self.to_dict(value_type='choice_and_literal'),
|
1610
1624
|
False,
|
1611
1625
|
verbose,
|
1612
1626
|
root_indent,
|
1613
|
-
**kwargs
|
1627
|
+
**kwargs,
|
1628
|
+
)
|
1614
1629
|
s = f'DNA({details})'
|
1615
1630
|
else:
|
1616
1631
|
if 'list_wrap_threshold' not in kwargs:
|
@@ -1621,7 +1636,7 @@ class DNA(symbolic.Object):
|
|
1621
1636
|
elif self.is_leaf:
|
1622
1637
|
s = f'DNA({self.value!r})'
|
1623
1638
|
else:
|
1624
|
-
rep =
|
1639
|
+
rep = utils.format(
|
1625
1640
|
self.to_json(compact=True, type_info=False),
|
1626
1641
|
compact,
|
1627
1642
|
verbose,
|
pyglove/core/geno/base_test.py
CHANGED
@@ -11,12 +11,10 @@
|
|
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
|
-
"""Tests for pyglove.geno.DNA."""
|
15
|
-
|
16
14
|
import unittest
|
17
15
|
|
18
|
-
from pyglove.core import object_utils
|
19
16
|
from pyglove.core import symbolic
|
17
|
+
from pyglove.core import utils
|
20
18
|
from pyglove.core.geno.base import ConditionalKey
|
21
19
|
from pyglove.core.geno.base import DNA
|
22
20
|
from pyglove.core.geno.categorical import manyof
|
@@ -1144,7 +1142,7 @@ class ConditionalKeyTest(unittest.TestCase):
|
|
1144
1142
|
self.assertEqual(key.num_choices, 5)
|
1145
1143
|
|
1146
1144
|
def test_to_str(self):
|
1147
|
-
key =
|
1145
|
+
key = utils.KeyPath(['a', ConditionalKey(1, 5), 'b'])
|
1148
1146
|
self.assertEqual(str(key), 'a[=1/5].b')
|
1149
1147
|
|
1150
1148
|
|
pyglove/core/geno/categorical.py
CHANGED
@@ -18,10 +18,9 @@ import re
|
|
18
18
|
import types
|
19
19
|
from typing import Any, List, Optional, Union
|
20
20
|
|
21
|
-
from pyglove.core import object_utils
|
22
21
|
from pyglove.core import symbolic
|
23
22
|
from pyglove.core import typing as pg_typing
|
24
|
-
|
23
|
+
from pyglove.core import utils
|
25
24
|
from pyglove.core.geno.base import DecisionPoint
|
26
25
|
from pyglove.core.geno.base import DNA
|
27
26
|
from pyglove.core.geno.base import DNASpec
|
@@ -139,14 +138,15 @@ class Choices(DecisionPoint):
|
|
139
138
|
for i in range(self.num_choices):
|
140
139
|
subchoice_spec = Choices(
|
141
140
|
subchoice_index=i,
|
142
|
-
location=
|
141
|
+
location=utils.KeyPath(i),
|
143
142
|
num_choices=1,
|
144
143
|
candidates=self.candidates,
|
145
144
|
literal_values=self.literal_values,
|
146
145
|
distinct=self.distinct,
|
147
146
|
sorted=self.sorted,
|
148
147
|
name=self.name,
|
149
|
-
hints=self.hints
|
148
|
+
hints=self.hints,
|
149
|
+
)
|
150
150
|
self._decision_points.extend(subchoice_spec.decision_points)
|
151
151
|
subchoice_specs.append(subchoice_spec)
|
152
152
|
self._subchoice_specs = symbolic.List(subchoice_specs)
|
@@ -158,7 +158,8 @@ class Choices(DecisionPoint):
|
|
158
158
|
self._decision_points.extend(c.decision_points)
|
159
159
|
|
160
160
|
def _update_children_paths(
|
161
|
-
self, old_path:
|
161
|
+
self, old_path: utils.KeyPath, new_path: utils.KeyPath
|
162
|
+
):
|
162
163
|
"""Trigger path change for subchoices so their IDs can be invalidated."""
|
163
164
|
super()._update_children_paths(old_path, new_path)
|
164
165
|
if self._subchoice_specs:
|
@@ -337,7 +338,7 @@ class Choices(DecisionPoint):
|
|
337
338
|
f'DNA child values should be sorted. '
|
338
339
|
f'Encountered: {sub_dna_values}, Location: {self.location.path}.')
|
339
340
|
for i, sub_dna in enumerate(dna):
|
340
|
-
sub_location =
|
341
|
+
sub_location = utils.KeyPath(i, self.location)
|
341
342
|
if not isinstance(sub_dna.value, int):
|
342
343
|
raise ValueError(
|
343
344
|
f'Choice value should be int. Encountered: {sub_dna.value}, '
|
@@ -601,13 +602,18 @@ class Choices(DecisionPoint):
|
|
601
602
|
kvlist = [('id', str(self.id), '\'\'')]
|
602
603
|
else:
|
603
604
|
kvlist = []
|
604
|
-
additionl_properties =
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
605
|
+
additionl_properties = utils.kvlist_str(
|
606
|
+
kvlist
|
607
|
+
+ [
|
608
|
+
('name', self.name, None),
|
609
|
+
('distinct', self.distinct, True),
|
610
|
+
('sorted', self.sorted, False),
|
611
|
+
('hints', self.hints, None),
|
612
|
+
('subchoice_index', self.subchoice_index, None),
|
613
|
+
],
|
614
|
+
compact=False,
|
615
|
+
root_indent=root_indent,
|
616
|
+
)
|
611
617
|
if additionl_properties:
|
612
618
|
s.append(', ')
|
613
619
|
s.append(additionl_properties)
|
@@ -615,14 +621,16 @@ class Choices(DecisionPoint):
|
|
615
621
|
return ''.join(s)
|
616
622
|
|
617
623
|
|
618
|
-
def manyof(
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
624
|
+
def manyof(
|
625
|
+
num_choices: int,
|
626
|
+
candidates: List[DNASpec],
|
627
|
+
distinct: bool = True,
|
628
|
+
sorted: bool = False, # pylint: disable=redefined-builtin
|
629
|
+
literal_values: Optional[List[Union[str, int, float]]] = None,
|
630
|
+
hints: Any = None,
|
631
|
+
location: Union[str, utils.KeyPath] = utils.KeyPath(),
|
632
|
+
name: Optional[str] = None,
|
633
|
+
) -> Choices:
|
626
634
|
"""Returns a multi-choice specification.
|
627
635
|
|
628
636
|
It creates the genotype for :func:`pyglove.manyof`.
|
@@ -674,11 +682,13 @@ def manyof(num_choices: int,
|
|
674
682
|
hints=hints, location=location, name=name)
|
675
683
|
|
676
684
|
|
677
|
-
def oneof(
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
685
|
+
def oneof(
|
686
|
+
candidates: List[DNASpec],
|
687
|
+
literal_values: Optional[List[Union[str, int, float]]] = None,
|
688
|
+
hints: Any = None,
|
689
|
+
location: Union[str, utils.KeyPath] = utils.KeyPath(),
|
690
|
+
name: Optional[str] = None,
|
691
|
+
) -> Choices:
|
682
692
|
"""Returns a single choice specification.
|
683
693
|
|
684
694
|
It creates the genotype for :func:`pyglove.oneof`.
|
@@ -716,4 +726,3 @@ def oneof(candidates: List[DNASpec],
|
|
716
726
|
"""
|
717
727
|
return manyof(1, candidates, literal_values=literal_values,
|
718
728
|
hints=hints, location=location, name=name)
|
719
|
-
|
pyglove/core/geno/custom.py
CHANGED
@@ -17,10 +17,9 @@ import random
|
|
17
17
|
import types
|
18
18
|
from typing import Any, Callable, List, Optional, Union
|
19
19
|
|
20
|
-
from pyglove.core import object_utils
|
21
20
|
from pyglove.core import symbolic
|
22
21
|
from pyglove.core import typing as pg_typing
|
23
|
-
|
22
|
+
from pyglove.core import utils
|
24
23
|
from pyglove.core.geno.base import DecisionPoint
|
25
24
|
from pyglove.core.geno.base import DNA
|
26
25
|
|
@@ -125,7 +124,7 @@ class CustomDecisionPoint(DecisionPoint):
|
|
125
124
|
f'CustomDecisionPoint expects string type DNA. '
|
126
125
|
f'Encountered: {dna!r}, Location: {self.location.path}.')
|
127
126
|
|
128
|
-
def sym_jsonify(self, **kwargs: Any) ->
|
127
|
+
def sym_jsonify(self, **kwargs: Any) -> utils.JSONValueType:
|
129
128
|
"""Overrides sym_jsonify to exclude non-serializable fields."""
|
130
129
|
exclude_keys = kwargs.pop('exclude_keys', [])
|
131
130
|
exclude_keys.extend(['random_dna_fn', 'next_dna_fn'])
|
@@ -153,21 +152,25 @@ class CustomDecisionPoint(DecisionPoint):
|
|
153
152
|
kvlist = [('id', str(self.id), '\'\'')]
|
154
153
|
else:
|
155
154
|
kvlist = []
|
156
|
-
details =
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
155
|
+
details = utils.kvlist_str(
|
156
|
+
kvlist
|
157
|
+
+ [
|
158
|
+
('hyper_type', self.hyper_type, None),
|
159
|
+
('name', self.name, None),
|
160
|
+
('hints', self.hints, None),
|
161
|
+
]
|
162
|
+
)
|
161
163
|
return f'{self.__class__.__name__}({details})'
|
162
164
|
|
163
165
|
|
164
|
-
def custom(
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
166
|
+
def custom(
|
167
|
+
hyper_type: Optional[str] = None,
|
168
|
+
next_dna_fn: Optional[Callable[[Optional[DNA]], Optional[DNA]]] = None,
|
169
|
+
random_dna_fn: Optional[Callable[[Any], DNA]] = None,
|
170
|
+
hints: Any = None,
|
171
|
+
location: utils.KeyPath = utils.KeyPath(),
|
172
|
+
name: Optional[str] = None,
|
173
|
+
) -> CustomDecisionPoint:
|
171
174
|
"""Returns a custom decision point.
|
172
175
|
|
173
176
|
It creates the genotype for subclasses of :func:`pyglove.hyper.CustomHyper`.
|
pyglove/core/geno/numerical.py
CHANGED
@@ -17,10 +17,9 @@ import random
|
|
17
17
|
import types
|
18
18
|
from typing import Any, List, Optional, Union
|
19
19
|
|
20
|
-
from pyglove.core import object_utils
|
21
20
|
from pyglove.core import symbolic
|
22
21
|
from pyglove.core import typing as pg_typing
|
23
|
-
|
22
|
+
from pyglove.core import utils
|
24
23
|
from pyglove.core.geno.base import DecisionPoint
|
25
24
|
from pyglove.core.geno.base import DNA
|
26
25
|
|
@@ -167,22 +166,27 @@ class Float(DecisionPoint):
|
|
167
166
|
kvlist = [('id', str(self.id), '\'\'')]
|
168
167
|
else:
|
169
168
|
kvlist = []
|
170
|
-
details =
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
169
|
+
details = utils.kvlist_str(
|
170
|
+
kvlist
|
171
|
+
+ [
|
172
|
+
('name', self.name, None),
|
173
|
+
('min_value', self.min_value, None),
|
174
|
+
('max_value', self.max_value, None),
|
175
|
+
('scale', self.scale, None),
|
176
|
+
('hints', self.hints, None),
|
177
|
+
]
|
178
|
+
)
|
177
179
|
return f'{self.__class__.__name__}({details})'
|
178
180
|
|
179
181
|
|
180
|
-
def floatv(
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
182
|
+
def floatv(
|
183
|
+
min_value: float,
|
184
|
+
max_value: float,
|
185
|
+
scale: Optional[str] = None,
|
186
|
+
hints: Any = None,
|
187
|
+
location: utils.KeyPath = utils.KeyPath(),
|
188
|
+
name: Optional[str] = None,
|
189
|
+
) -> Float:
|
186
190
|
"""Returns a Float specification.
|
187
191
|
|
188
192
|
It creates the genotype for :func:`pyglove.floatv`.
|
@@ -226,4 +230,3 @@ def floatv(min_value: float,
|
|
226
230
|
"""
|
227
231
|
return Float(min_value, max_value, scale,
|
228
232
|
hints=hints, location=location, name=name)
|
229
|
-
|
pyglove/core/geno/space.py
CHANGED
@@ -18,10 +18,9 @@ import random
|
|
18
18
|
import types
|
19
19
|
from typing import List, Optional, Union
|
20
20
|
|
21
|
-
from pyglove.core import object_utils
|
22
21
|
from pyglove.core import symbolic
|
23
22
|
from pyglove.core import typing as pg_typing
|
24
|
-
|
23
|
+
from pyglove.core import utils
|
25
24
|
from pyglove.core.geno.base import DecisionPoint
|
26
25
|
from pyglove.core.geno.base import DNA
|
27
26
|
from pyglove.core.geno.base import DNASpec
|
@@ -231,8 +230,8 @@ class Space(DNASpec):
|
|
231
230
|
return sum([len(elem) for elem in self.elements])
|
232
231
|
|
233
232
|
def __getitem__(
|
234
|
-
self, index: Union[int, slice, str,
|
235
|
-
|
233
|
+
self, index: Union[int, slice, str, utils.KeyPath]
|
234
|
+
) -> Union[DecisionPoint, List[DecisionPoint]]:
|
236
235
|
"""Operator [] to return element by index or sub-DNASpec by name."""
|
237
236
|
if isinstance(index, (int, slice)):
|
238
237
|
return self.elements[index]
|
pyglove/core/hyper/base.py
CHANGED
@@ -18,9 +18,9 @@ import abc
|
|
18
18
|
from typing import Any, Callable, Optional
|
19
19
|
|
20
20
|
from pyglove.core import geno
|
21
|
-
from pyglove.core import object_utils
|
22
21
|
from pyglove.core import symbolic
|
23
22
|
from pyglove.core import typing as pg_typing
|
23
|
+
from pyglove.core import utils
|
24
24
|
|
25
25
|
|
26
26
|
class HyperValue(symbolic.NonDeterministic): # pytype: disable=ignored-metaclass
|
@@ -110,8 +110,7 @@ class HyperValue(symbolic.NonDeterministic): # pytype: disable=ignored-metaclas
|
|
110
110
|
"""
|
111
111
|
|
112
112
|
@abc.abstractmethod
|
113
|
-
def dna_spec(self,
|
114
|
-
location: Optional[object_utils.KeyPath] = None) -> geno.DNASpec:
|
113
|
+
def dna_spec(self, location: Optional[utils.KeyPath] = None) -> geno.DNASpec:
|
115
114
|
"""Get DNA spec of DNA that is decodable/encodable by this hyper value."""
|
116
115
|
|
117
116
|
|
@@ -186,12 +185,13 @@ def set_dynamic_evaluate_fn(
|
|
186
185
|
global _global_dynamic_evaluate_fn
|
187
186
|
if per_thread:
|
188
187
|
assert _global_dynamic_evaluate_fn is None, _global_dynamic_evaluate_fn
|
189
|
-
|
188
|
+
utils.thread_local_set(_TLS_KEY_DYNAMIC_EVALUATE_FN, fn)
|
190
189
|
else:
|
191
190
|
_global_dynamic_evaluate_fn = fn
|
192
191
|
|
193
192
|
|
194
193
|
def get_dynamic_evaluate_fn() -> Optional[Callable[[HyperValue], Any]]:
|
195
194
|
"""Gets current dynamic evaluate function."""
|
196
|
-
return
|
197
|
-
_TLS_KEY_DYNAMIC_EVALUATE_FN, _global_dynamic_evaluate_fn
|
195
|
+
return utils.thread_local_get(
|
196
|
+
_TLS_KEY_DYNAMIC_EVALUATE_FN, _global_dynamic_evaluate_fn
|
197
|
+
)
|