Skip to content

Commit

Permalink
Internal
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 711483900
  • Loading branch information
daiyip authored and pyglove authors committed Jan 4, 2025
1 parent a4e5373 commit 98edcb6
Show file tree
Hide file tree
Showing 92 changed files with 1,910 additions and 1,638 deletions.
4 changes: 1 addition & 3 deletions docs/api/docgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,11 @@
'hyper',
'io',
'patching',
'object_utils',
'utils',
'symbolic',
'views',
'tuning',
'typing',

# Ext.
'early_stopping',
'evolution',
Expand All @@ -73,7 +72,6 @@
'evolution.recombinators',
'mutfun',
'scalars',

# generators.
'generators',
})
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ def noramlized_title_and_target(api, attr_name=None):
exclude_patterns = [
# Temporarily disable sources for faster sphinx-build
# 'api/core/symbolic',
# 'api/core/object_utils',
# 'api/core/utils',
# 'api/core/typing',
# 'api/core/detouring',
# 'api/core/wrapping',
Expand Down
2 changes: 1 addition & 1 deletion docs/learn/soop/som/definition.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Symbolic Tree
A symbolic attribute is usually a value of simple type (e.g. :class:`int`, :class:`str``) or a reference
to another symbolic object. When multiple symbolic objects are linked together in this way, it forms
a tree-like structure of symbols. Each object in the tree is identified by a unique
combination of keys, which we call a *key path* (:class:`pg.KeyPath <pyglove.object_utils.KeyPath>`).
combination of keys, which we call a *key path* (:class:`pg.KeyPath <pyglove.utils.KeyPath>`).
Key paths can be used to navigate and manipulate specific nodes in the symbolic tree::

@pg.symbolize
Expand Down
2 changes: 1 addition & 1 deletion docs/learn/soop/som/events.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ which is triggered when any of the symbolic arguments are updated via
self._z = self.x ** 2

The ``_on_change`` event takes a ``updates`` argument, which is a dict of
:class:`pg.KeyPath <pyglove.object_utils.KeyPath>` to
:class:`pg.KeyPath <pyglove.utils.KeyPath>` to
:class:`pg.FieldUpdate <pyglove.symbolic.FieldUpdate>` objects
in case the user want to cherrypick the internal states to recompute based
on the updates. For example::
Expand Down
6 changes: 3 additions & 3 deletions docs/learn/soop/som/operations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ Location
========

Each symbolic object has a unique location within a symbolic tree, represented a key path
(:class:`pg.KeyPath <pyglove.object_utils.KeyPath>`), which is a path consists of the keys
(:class:`pg.KeyPath <pyglove.utils.KeyPath>`), which is a path consists of the keys
from the root node to the current node.

For example, ``a.b[0].c`` is a path with height 4:
Expand Down Expand Up @@ -331,7 +331,7 @@ human-readable format can be shown during debugging:
* ``__str__`` formats a symbolic tree into a multi-line string
representation, which is usually used in debugging purposes.

Both of these methods are based on :func:`pg.format <pyglove.object_utils.format>`, which provides a
Both of these methods are based on :func:`pg.format <pyglove.utils.format>`, which provides a
rich set of features for formatting symbolic trees. For example, exclude
the keys that have the default values from the string representation::

Expand Down Expand Up @@ -506,7 +506,7 @@ objects that are merely representations. Here is a summary of operations that de
- :meth:`~pyglove.symbolic.Symbolic.sym_abstract`
- Test whether an object is abstract or not.

* - :func:`pg.is_partial <pyglove.object_utils.is_partial>`
* - :func:`pg.is_partial <pyglove.utils.is_partial>`
- :meth:`~pyglove.symbolic.Symbolic.sym_partial`
- Test whether an object is partial or not.

Expand Down
2 changes: 1 addition & 1 deletion docs/learn/soop/som/validation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -220,4 +220,4 @@ By default, PyGlove registered converters between the following pairs:
- :class:`datetime.datetime`

* - :class:`str`
- :class:`pg.KeyPath <pyglove.object_utils.KeyPath>`
- :class:`pg.KeyPath <pyglove.utils.KeyPath>`
45 changes: 24 additions & 21 deletions pyglove/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@
|__ tuning : Interface for program tuning with a local backend.
|__ detouring : Detouring classes creation without symbolic types.
|__ patching : Patching a program with URL-like strings.
|__ object_utils : Utility libary on operating with Python objects.
|__ utils : Utility libary on operating with Python objects.
"""

# NOTE(daiyip): We disable bad-import-order to preserve the relation of
Expand Down Expand Up @@ -273,31 +272,35 @@


#
# Symbols from 'object_utils' sub-module.
# Symbols from 'utils' sub-module.
#

from pyglove.core import object_utils
KeyPath = object_utils.KeyPath
KeyPathSet = object_utils.KeyPathSet
MISSING_VALUE = object_utils.MISSING_VALUE
from pyglove.core import utils

# For backward compatibility.
object_utils = utils

KeyPath = utils.KeyPath
KeyPathSet = utils.KeyPathSet
MISSING_VALUE = utils.MISSING_VALUE

Formattable = object_utils.Formattable
repr_format = object_utils.repr_format
str_format = object_utils.str_format
Formattable = utils.Formattable
repr_format = utils.repr_format
str_format = utils.str_format

MaybePartial = object_utils.MaybePartial
JSONConvertible = object_utils.JSONConvertible
DocStr = object_utils.DocStr
MaybePartial = utils.MaybePartial
JSONConvertible = utils.JSONConvertible
DocStr = utils.DocStr

registered_types = object_utils.registered_types
explicit_method_override = object_utils.explicit_method_override
registered_types = utils.registered_types
explicit_method_override = utils.explicit_method_override

is_partial = object_utils.is_partial
format = object_utils.format # pylint: disable=redefined-builtin
print = object_utils.print # pylint: disable=redefined-builtin
docstr = object_utils.docstr
catch_errors = object_utils.catch_errors
timeit = object_utils.timeit
is_partial = utils.is_partial
format = utils.format # pylint: disable=redefined-builtin
print = utils.print # pylint: disable=redefined-builtin
docstr = utils.docstr
catch_errors = utils.catch_errors
timeit = utils.timeit

# Symbols from 'views' sub-module.

Expand Down
91 changes: 53 additions & 38 deletions pyglove/core/geno/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
import types
from typing import Any, Callable, Dict, List, Optional, Tuple, Union

from pyglove.core import object_utils
from pyglove.core import symbolic
from pyglove.core import typing as pg_typing
from pyglove.core import utils


class AttributeDict(dict):
Expand All @@ -37,12 +37,20 @@ def __setattr__(self, key: Any, value: Any) -> None:


@symbolic.members([
('location',
pg_typing.Object(object_utils.KeyPath, default=object_utils.KeyPath()),
('KeyPath of associated genetic encoder relative to parent object '
'template. This allows DNA generator to apply rule based on locations.')),
('hints',
pg_typing.Any(default=None), 'Hints for DNA generator to consume.')
(
'location',
pg_typing.Object(utils.KeyPath, default=utils.KeyPath()),
(
'KeyPath of associated genetic encoder relative to parent object'
' template. This allows DNA generator to apply rule based on'
' locations.'
),
),
(
'hints',
pg_typing.Any(default=None),
'Hints for DNA generator to consume.',
),
])
class DNASpec(symbolic.Object):
"""Base class for DNA specifications (genotypes).
Expand Down Expand Up @@ -175,7 +183,7 @@ def decision_points(self) -> List['DecisionPoint']:
"""Returns all decision points in their declaration order."""

@property
def decision_ids(self) -> List[object_utils.KeyPath]:
def decision_ids(self) -> List[utils.KeyPath]:
"""Returns decision IDs."""
return list(self._decision_point_by_id.keys())

Expand Down Expand Up @@ -286,7 +294,7 @@ def parent_choice(self) -> Optional['DecisionPoint']:
return self.parent_spec if self.is_space else self.parent_spec.parent_choice

@property
def id(self) -> object_utils.KeyPath:
def id(self) -> utils.KeyPath:
"""Returns a path of locations from the root as the ID for current node."""
if self._id is None:
parent = self.parent_spec
Expand All @@ -295,28 +303,29 @@ def id(self) -> object_utils.KeyPath:
elif self.is_space:
assert parent.is_categorical, parent
assert self.index is not None
self._id = object_utils.KeyPath(
ConditionalKey(self.index, len(parent.candidates)),
parent.id) + self.location
self._id = (
utils.KeyPath(
ConditionalKey(self.index, len(parent.candidates)), parent.id
)
+ self.location
)
else:
# Float() or a multi-choice spec of a parent Choice.
self._id = parent.id + self.location
return self._id

def get(self,
name_or_id: Union[object_utils.KeyPath, str],
default: Any = None
) -> Union['DecisionPoint', List['DecisionPoint']]:
def get(
self, name_or_id: Union[utils.KeyPath, str], default: Any = None
) -> Union['DecisionPoint', List['DecisionPoint']]:
"""Get decision point(s) by name or ID."""
try:
return self[name_or_id]
except KeyError:
return default

def __getitem__(
self,
name_or_id: Union[object_utils.KeyPath, str]
) -> Union['DecisionPoint', List['DecisionPoint']]:
self, name_or_id: Union[utils.KeyPath, str]
) -> Union['DecisionPoint', List['DecisionPoint']]:
"""Get decision point(s) by name or ID ."""
v = self._named_decision_points.get(name_or_id, None)
if v is None:
Expand Down Expand Up @@ -475,7 +484,7 @@ class DNA(symbolic.Object):
# Allow assignment on symbolic attributes.
allow_symbolic_assignment = True

@object_utils.explicit_method_override
@utils.explicit_method_override
def __init__(
self,
value: Union[None, int, float, str, List[Any], Tuple[Any]] = None,
Expand Down Expand Up @@ -727,7 +736,7 @@ def _decision_by_id(self):
return self._decision_by_id_cache

@property
def decision_ids(self) -> List[object_utils.KeyPath]:
def decision_ids(self) -> List[utils.KeyPath]:
"""Returns decision IDs."""
self._ensure_dna_spec()
return self._spec.decision_ids
Expand Down Expand Up @@ -1249,9 +1258,11 @@ def _bind_decisions(dna_spec):
return dna

def to_numbers(
self, flatten: bool = True,
) -> Union[List[Union[int, float, str]],
object_utils.Nestable[Union[int, float, str]]]:
self,
flatten: bool = True,
) -> Union[
List[Union[int, float, str]], utils.Nestable[Union[int, float, str]]
]:
"""Returns a (maybe) nested structure of numbers as decisions.
Args:
Expand Down Expand Up @@ -1338,7 +1349,7 @@ def from_fn(
f'Location: {dna_spec.location.path}.')
children = []
for i, choice in enumerate(decision):
choice_location = object_utils.KeyPath(i, dna_spec.location)
choice_location = utils.KeyPath(i, dna_spec.location)
if not isinstance(choice, int):
raise ValueError(
f'Choice value should be int. Encountered: {choice}, '
Expand Down Expand Up @@ -1410,7 +1421,7 @@ def sym_jsonify(

if type_info:
json_value = {
object_utils.JSONConvertible.TYPE_NAME_KEY: (
utils.JSONConvertible.TYPE_NAME_KEY: (
self.__class__.__serialization_key__
),
'format': 'compact',
Expand All @@ -1435,7 +1446,8 @@ def from_json(
json_value: Dict[str, Any],
*,
allow_partial: bool = False,
root_path: Optional[object_utils.KeyPath] = None) -> 'DNA':
root_path: Optional[utils.KeyPath] = None,
) -> 'DNA':
"""Class method that load a DNA from a JSON value.
Args:
Expand Down Expand Up @@ -1472,8 +1484,8 @@ def is_leaf(self) -> bool:
return not self.children

def __getitem__(
self, key: Union[int, slice, str, object_utils.KeyPath, 'DecisionPoint']
) -> Union[None, 'DNA', List[Optional['DNA']]]:
self, key: Union[int, slice, str, utils.KeyPath, 'DecisionPoint']
) -> Union[None, 'DNA', List[Optional['DNA']]]:
"""Get an immediate child DNA or DNA in the sub-tree.
Args:
Expand Down Expand Up @@ -1504,10 +1516,11 @@ def __getitem__(
v = self._decision_by_id[key]
return v

def get(self,
key: Union[int, slice, str, object_utils.KeyPath, 'DecisionPoint'],
default: Any = None
) -> Union[Any, None, 'DNA', List[Optional['DNA']]]:
def get(
self,
key: Union[int, slice, str, utils.KeyPath, 'DecisionPoint'],
default: Any = None,
) -> Union[Any, None, 'DNA', List[Optional['DNA']]]:
"""Get an immediate child DNA or DNA in the sub-tree."""
try:
return self[key]
Expand All @@ -1529,8 +1542,9 @@ def __contains__(self, dna_or_value: Union[int, 'DNA']) -> bool:
return True
else:
raise ValueError(
f'DNA.__contains__ does not accept '
f'{object_utils.quote_if_str(dna_or_value)!r}.')
'DNA.__contains__ does not accept '
f'{utils.quote_if_str(dna_or_value)!r}.'
)
return False

def __hash__(self):
Expand Down Expand Up @@ -1605,12 +1619,13 @@ def format(
):
"""Customize format method for DNA for more compact representation."""
if as_dict and self.spec:
details = object_utils.format(
details = utils.format(
self.to_dict(value_type='choice_and_literal'),
False,
verbose,
root_indent,
**kwargs)
**kwargs,
)
s = f'DNA({details})'
else:
if 'list_wrap_threshold' not in kwargs:
Expand All @@ -1621,7 +1636,7 @@ def format(
elif self.is_leaf:
s = f'DNA({self.value!r})'
else:
rep = object_utils.format(
rep = utils.format(
self.to_json(compact=True, type_info=False),
compact,
verbose,
Expand Down
6 changes: 2 additions & 4 deletions pyglove/core/geno/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for pyglove.geno.DNA."""

import unittest

from pyglove.core import object_utils
from pyglove.core import symbolic
from pyglove.core import utils
from pyglove.core.geno.base import ConditionalKey
from pyglove.core.geno.base import DNA
from pyglove.core.geno.categorical import manyof
Expand Down Expand Up @@ -1144,7 +1142,7 @@ def test_basics(self):
self.assertEqual(key.num_choices, 5)

def test_to_str(self):
key = object_utils.KeyPath(['a', ConditionalKey(1, 5), 'b'])
key = utils.KeyPath(['a', ConditionalKey(1, 5), 'b'])
self.assertEqual(str(key), 'a[=1/5].b')


Expand Down
Loading

0 comments on commit 98edcb6

Please sign in to comment.