pygx.hyper¶
Hyper objects: representing template-based object space.
hyper
¶
Hyper objects: representing template-based object space.
In PyGX, an object space is represented by a hyper object, which is an
symbolic object that is placeheld by hyper primitives
(pg.hyper.HyperPrimitive). Through hyper objects, object templates
(pg.hyper.ObjectTemplate) can be obtained to generate objects
based on program genomes (pg.DNA).
.. graphviz:: :align: center
digraph hypers {
node [shape="box"];
edge [arrowtail="empty" arrowhead="none" dir="back" style="dashed"];
hyper [label="HyperValue" href="hyper_value.html"];
template [label="ObjectTemplate" href="object_template.html"];
primitive [label="HyperPrimitive" href="hyper_primitive.html"];
choices [label="Choices" href="choices.html"];
oneof [label="OneOf" href="oneof_class.html"];
manyof [label="ManyOf" href="manyof_class.html"];
float [label="Float" href="float.html"];
custom [label="CustomHyper" href="custom_hyper.html"];
evolve [label="Evolvable" href="evolvable.html"];
hyper -> template;
hyper -> primitive;
primitive -> choices;
choices -> oneof;
choices -> manyof;
primitive -> float;
primitive -> custom;
custom -> evolve;
}
Hyper values map 1:1 to genotypes as the following:
+---------------------------------+----------------------------------------+
| Hyper class | Genotype class |
+=================================+========================================+
|pg.hyper.HyperValue |pg.DNASpec |
+---------------------------------+----------------------------------------+
|pg.hyper.ObjectTemplate |pg.geno.Space |
+---------------------------------+----------------------------------------+
|pg.hyper.HyperPrimitive |pg.geno.DecisionPoint |
+---------------------------------+----------------------------------------+
|pg.hyper.Choices |pg.geno.Choices |
+---------------------------------+----------------------------------------+
|pg.hyper.Float |pg.geno.Float |
+---------------------------------+----------------------------------------+
|pg.hyper.CustomHyper |pg.geno.CustomDecisionPoint |
+---------------------------------+----------------------------------------+
HyperPrimitive
¶
HyperPrimitive(
*,
allow_partial: bool = False,
sealed: bool | None = None,
root_path: KeyPath | None = None,
explicit_init: bool = False,
**kwargs: Any
)
Bases: Object, HyperValue
Base class for hyper primitives.
A hyper primitive is a pure symbolic object which represents an object
generation rule. It correspond to a decision point
(pygx.geno.DecisionPoint) in the algorithm's view.
Child classes:
Source code in pygx/symbolic/_object.py
2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 | |
HyperValue
¶
Bases: NonDeterministic
Base class for a hyper value.
Hyper value represents a space of objects, which is essential for programmatically generating objects. It can encode a concrete object into a DNA, or decode a DNA into a concrete object.
DNA is a nestable numeric interface we use to generate object (see geno.py).
Each position in the DNA represents either the index of a choice, or a value
itself is numeric. There could be multiple choices standing side-by-side,
representing knobs on different parts of an object, or choices being chained,
forming conditional choice spaces, which can be described by a tree structure.
Hyper values form a tree as the following:
.. graphviz::
digraph relationship { template [label="ObjectTemplate" href="object_template.html"]; primitive [label="HyperPrimitive" href="hyper_primitive.html"]; choices [label="OneOf/ManyOf" href="choices.html"]; float [label="Float" href="float_class.html"]; custom [label="CustomHyper" href="custom_hyper.html"]; template -> primitive [label="elements (1:)"]; primitive -> choices [dir="back" arrowtail="empty" style="dashed"]; primitive -> float [dir="back" arrowtail="empty" style="dashed"]; primitive -> custom [dir="back" arrowtail="empty" style="dashed"]; choices -> template [label="candidates (1:)"]; }
Source code in pygx/hyper/_base.py
set_dna
¶
set_dna(dna: DNA) -> None
Use this DNA to generate value.
NOTE(daiyip): self.dna is only used in __call_. Thus 'set_dna' can be called multiple times to generate different values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dna
|
DNA
|
DNA to use to decode the value. |
required |
Source code in pygx/hyper/_base.py
encode
abstractmethod
¶
encode(value: Any) -> DNA
Encode a value into a DNA.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
A value that conforms to the hyper value definition. |
required |
Returns:
| Type | Description |
|---|---|
DNA
|
DNA for the value. |
dna_spec
abstractmethod
¶
Choices
¶
Choices(
*,
allow_partial: bool = False,
sealed: bool | None = None,
root_path: KeyPath | None = None,
explicit_init: bool = False,
**kwargs: Any
)
Bases: HyperPrimitive
Categorical choices from a list of candidates.
Example::
# A single categorical choice: v = pg.oneof([1, 2, 3])
# A multiple categorical choice as a list: vs = pg.manyof(2, [1, 2, 3])
# A hierarchical categorical choice: v2 = pg.oneof([ 'foo', 'bar', pg.manyof(2, [1, 2, 3]) ])
See also:
Source code in pygx/symbolic/_object.py
2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 | |
on_sym_bound
¶
On members are bound.
Source code in pygx/hyper/_categorical.py
dna_spec
¶
Returns corresponding DNASpec.
Source code in pygx/hyper/_categorical.py
encode
¶
encode(value: list[Any]) -> DNA
Encode a list of values into DNA.
Example::
# DNA of an object containing a single OneOf.
# {'a': 1} => DNA(0)
{
'a': one_of([1, 2])
}
# DNA of an object containing multiple OneOfs.
# {'b': 1, 'c': bar} => DNA([0, 1])
{
'b': pg.oneof([1, 2]),
'c': pg.oneof(['foo', 'bar'])
}
# DNA of an object containing conditional space.
# {'a': {'b': 1} => DNA(0, 0, 0)])
# {'a': {'b': [4, 7]} => DNA(1, [(0, 1), 2])
# {'a': {'b': 'bar'} => DNA(2)
{
'a': {
'b': pg.oneof([
pg.oneof([
pg.oneof([1, 2]),
pg.oneof(3, 4)]),
pg.manyof(2, [
pg.oneof([4, 5]),
6,
7
]),
]),
'bar',
])
}
}
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
list[Any]
|
A list of value that can match choice candidates. |
required |
Returns:
| Type | Description |
|---|---|
DNA
|
Encoded DNA. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in pygx/hyper/_categorical.py
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | |
ManyOf
¶
ManyOf(
*,
allow_partial: bool = False,
sealed: bool | None = None,
root_path: KeyPath | None = None,
explicit_init: bool = False,
**kwargs: Any
)
Bases: Choices
N Choose K.
Example::
# Chooses 2 distinct candidates. v = pg.manyof(2, [1, 2, 3])
# Chooses 2 non-distinct candidates. v = pg.manyof(2, [1, 2, 3], distinct=False)
# Chooses 2 distinct candidates sorted by their indices. v = pg.manyof(2, [1, 2, 3], sorted=True)
# Permutates the candidates. v = pg.permutate([1, 2, 3])
# A hierarchical categorical choice: v2 = pg.manyof(2, [ 'foo', 'bar', pg.oneof([1, 2, 3]) ])
See also:
pygx.manyofpygx.permutatepygx.hyper.Choicespygx.hyper.OneOfpygx.hyper.Floatpygx.hyper.CustomHyper
Source code in pygx/symbolic/_object.py
2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 | |
custom_apply
¶
custom_apply(
path: KeyPath,
value_spec: ValueSpec,
allow_partial: bool,
child_transform: None | Callable[[KeyPath, Field, Any], Any] = None,
) -> tuple[bool, Choices]
Validate candidates during value_spec binding time.
Source code in pygx/hyper/_categorical.py
OneOf
¶
OneOf(
*,
allow_partial: bool = False,
sealed: bool | None = None,
root_path: KeyPath | None = None,
explicit_init: bool = False,
**kwargs: Any
)
Bases: Choices
N Choose 1.
Example::
# A single categorical choice: v = pg.oneof([1, 2, 3])
# A hierarchical categorical choice: v2 = pg.oneof([ 'foo', 'bar', pg.oneof([1, 2, 3]) ])
See also:
Source code in pygx/symbolic/_object.py
2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 | |
on_sym_bound
¶
encode
¶
encode(value: Any) -> DNA
Encode a value into a DNA.
Source code in pygx/hyper/_categorical.py
custom_apply
¶
custom_apply(
path: KeyPath,
value_spec: ValueSpec,
allow_partial: bool,
child_transform: None | Callable[[KeyPath, Field, Any], Any] = None,
) -> tuple[bool, OneOf]
Validate candidates during value_spec binding time.
Source code in pygx/hyper/_categorical.py
CustomHyper
¶
CustomHyper(
*,
allow_partial: bool = False,
sealed: bool | None = None,
root_path: KeyPath | None = None,
explicit_init: bool = False,
**kwargs: Any
)
Bases: HyperPrimitive
User-defined hyper primitive.
User-defined hyper primitive is useful when users want to have full control on the semantics and genome encoding of the search space. For example, the decision points are of variable length, which is not yet supported by built-in hyper primitives.
To use user-defined hyper primitive is simple, the user should:
1) Subclass CustomHyper and implements the
pygx.hyper.CustomHyper.custom_decode method.
It's optional to implement the
pygx.hyper.CustomHyper.custom_encode method, which is only
necessary when the user want to encoder a material object into a DNA.
2) Introduce a DNAGenerator that can generate DNA for the
pygx.geno.CustomDecisionPoint.
For example, the following code tries to find an optimal sub-sequence of an integer sequence by their sums::
import random
class IntSequence(pg.hyper.CustomHyper):
def custom_decode(self, dna):
return [int(v) for v in dna.value.split(',') if v != '']
class SubSequence(pg.algo.evolution.Mutator):
def mutate(self, dna):
genome = dna.value
items = genome.split(',')
start = random.randint(0, len(items))
end = random.randint(start, len(items))
new_genome = ','.join(items[start:end])
return pg.DNA(new_genome, spec=dna.spec)
@pg.geno.dna_generator def initial_population(): yield pg.DNA('12,-34,56,-2,100,98', spec=dna_spec)
algo = pg.algo.evolution.Evolution( (pg.algo.evolution.selectors.Random(10) >> pg.algo.evolution.selectors.Top(1) >> SubSequence()), population_init=initial_population(), population_update=pg.algo.evolution.selectors.Last(20))
best_reward, best_example = None, None for int_seq, feedback in pg.sample(IntSequence(), algo, num_examples=100): reward = sum(int_seq) if best_reward is None or best_reward < reward: best_reward, best_example = reward, int_seq feedback(reward)
print(best_reward, best_example)
Please note that user-defined hyper value can be used together with PyGX's built-in hyper primitives, for example::
pg.oneof([IntSequence(), None])
Therefore it's also a mechanism to extend PyGX's search space definitions.
Source code in pygx/symbolic/_object.py
2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 | |
dna_spec
¶
Always returns CustomDecisionPoint for CustomHyper.
Source code in pygx/hyper/_custom.py
first_dna
¶
first_dna() -> DNA
Returns the first DNA of current sub-space.
Returns:
| Type | Description |
|---|---|
DNA
|
A string-valued DNA. |
Source code in pygx/hyper/_custom.py
next_dna
¶
Subclasses should override this method to support pg.Sweeping.
random_dna
¶
random_dna(
random_generator: ModuleType | Random | None = None,
previous_dna: DNA | None = None,
) -> DNA
Subclasses should override this method to support pg.random_dna.
Source code in pygx/hyper/_custom.py
custom_apply
¶
custom_apply(
path: KeyPath,
value_spec: ValueSpec,
allow_partial: bool,
child_transform: None | Callable[[KeyPath, Field, Any], Any] = None,
) -> tuple[bool, CustomHyper]
Validate candidates during value_spec binding time.
Source code in pygx/hyper/_custom.py
DerivedValue
¶
DerivedValue(
*,
allow_partial: bool = False,
sealed: bool | None = None,
root_path: KeyPath | None = None,
explicit_init: bool = False,
**kwargs: Any
)
Bases: Object, CustomTyping
Base class of value that references to other values in object tree.
Source code in pygx/symbolic/_object.py
2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 | |
derive
abstractmethod
¶
resolve
¶
resolve(
reference_path_or_paths: str | list[str] | None = None,
) -> tuple[Symbolic, KeyPath] | list[tuple[Symbolic, KeyPath]]
Resolve reference paths based on the location of this node.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reference_path_or_paths
|
str | list[str] | None
|
(Optional) a string or KeyPath as a reference path or a list of strings or KeyPath objects as a list of reference paths. If this argument is not provided, prebound reference paths of this object will be used. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[Symbolic, KeyPath] | list[tuple[Symbolic, KeyPath]]
|
A tuple (or list of tuple) of (resolved parent, resolved full path) |
Source code in pygx/hyper/_derived.py
ValueReference
¶
Bases: DerivedValue
Class that represents a value referencing another value.
Source code in pygx/hyper/_derived.py
on_sym_bound
¶
derive
¶
Derive value by return a copy of the referenced value.
Source code in pygx/hyper/_derived.py
custom_apply
¶
custom_apply(
path: KeyPath,
value_spec: ValueSpec,
allow_partial: bool,
child_transform: None | Callable[[KeyPath, Field, Any], Any] = None,
) -> tuple[bool, DerivedValue]
Implement pg_typing.CustomTyping interface.
Source code in pygx/hyper/_derived.py
DynamicEvaluationContext
¶
DynamicEvaluationContext(
where: Callable[[HyperPrimitive], bool] | None = None,
require_hyper_name: bool = False,
per_thread: bool = True,
dna_spec: DNASpec | None = None,
)
Context for dynamic evaluation of hyper primitives.
Example::
import pygx as pg
# Define a function that implicitly declares a search space. def foo(): return pg.oneof(range(-10, 10)) ** 2 + pg.oneof(range(-10, 10)) ** 2
# Define the search space by running the foo once.
search_space = pg.hyper.DynamicEvaluationContext()
with search_space.collect():
_ = foo()
# Create a search algorithm. search_algorithm = pg.algo.evolution.regularized_evolution( pg.algo.evolution.mutators.Uniform(), population_size=32, tournament_size=16)
# Define the feedback loop.
best_foo, best_reward = None, None
for example, feedback in pg.sample(
search_space, search_algorithm, num_examples=100):
# Call to example returns a context manager
# under which the program is connected with
# current search algorithm decisions.
with example():
reward = foo()
feedback(reward)
if best_reward is None or best_reward < reward:
best_foo, best_reward = example, reward
Create a dynamic evaluation context.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
where
|
Callable[[HyperPrimitive], bool] | None
|
A callable object that decide whether a hyper primitive should be
included when being instantiated under |
None
|
require_hyper_name
|
bool
|
If True, all hyper primitives (e.g. pg.oneof) must
come with a |
False
|
per_thread
|
bool
|
If True, the context manager will be applied to current thread only. Otherwise, it will be applied on current process. |
True
|
dna_spec
|
DNASpec | None
|
External provided search space. If None, the dynamic evaluation
context can be used to create new search space via |
None
|
Source code in pygx/hyper/_dynamic_evaluation.py
per_thread
property
¶
Returns True if current context collects/applies decisions per thread.
is_external
property
¶
Returns True if the search space is defined by an external DNASpec.
hyper_dict
property
¶
hyper_dict: Dict | None
Returns collected hyper primitives as a dict.
None if current context is controlled by an external DNASpec.
collect
¶
collect() -> Iterator[Dict]
A context manager for collecting hyper primitives within this context.
Example::
context = DynamicEvaluationContext() with context.collect(): x = pg.oneof([1, 2, 3]) + pg.oneof([4, 5, 6])
# Will print 1 + 4 = 5. Meanwhile 2 hyper primitives will be registered # in the search space represented by the context. print(x)
Yields:
| Type | Description |
|---|---|
Dict
|
The hyper dict representing the search space. |
Source code in pygx/hyper/_dynamic_evaluation.py
add_decision_point
¶
add_decision_point(hyper_primitive: HyperPrimitive)
Registers a parameter with current context and return its first value.
Source code in pygx/hyper/_dynamic_evaluation.py
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | |
apply
¶
apply(decisions: DNA | list[int | float | str]) -> Iterator[None]
Context manager for applying decisions.
Example::
def fun():
return pg.oneof([1, 2, 3]) + pg.oneof([4, 5, 6])
context = DynamicEvaluationContext()
with context.collect():
fun()
with context.apply([0, 1]):
# Will print 6 (1 + 5).
print(fun())
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
decisions
|
DNA | list[int | float | str]
|
A DNA or a list of numbers or strings as decisions for currrent search space. |
required |
Yields:
| Type | Description |
|---|---|
None
|
None |
Source code in pygx/hyper/_dynamic_evaluation.py
evaluate
¶
evaluate(hyper_primitive: HyperPrimitive)
Evaluates a hyper primitive based on current decisions.
Source code in pygx/hyper/_dynamic_evaluation.py
Evolvable
¶
Evolvable(
*,
allow_partial: bool = False,
sealed: bool | None = None,
root_path: KeyPath | None = None,
explicit_init: bool = False,
**kwargs: Any
)
Bases: CustomHyper
Hyper primitive for evolving an arbitrary symbolic object.
Source code in pygx/symbolic/_object.py
2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 | |
mutation_points_and_weights
¶
mutation_points_and_weights(
value: Symbolic,
) -> tuple[list[MutationPoint], list[float]]
Returns mutation points with weights for a symbolic tree.
Source code in pygx/hyper/_evolvable.py
random_dna
¶
random_dna(
random_generator: ModuleType | Random | None = None,
previous_dna: DNA | None = None,
) -> DNA
Generates a random DNA.
Source code in pygx/hyper/_evolvable.py
mutate
¶
Returns the next value for a symbolic value.
Source code in pygx/hyper/_evolvable.py
MutationPoint
dataclass
¶
MutationPoint(
mutation_type: MutationType,
location: KeyPath,
old_value: Any,
parent: Symbolic | None,
)
Internal class that encapsulates the information for a mutation point.
Attributes:
| Name | Type | Description |
|---|---|---|
mutation_type |
MutationType
|
The type of the mutation. |
location |
KeyPath
|
The location where the mutation will take place. |
old_value |
Any
|
The value of the mutation point before mutation. |
parent |
Symbolic | None
|
The parent node of the mutation point. |
MutationType
¶
Bases: str, Enum
Mutation type.
Float
¶
Float(
*,
allow_partial: bool = False,
sealed: bool | None = None,
root_path: KeyPath | None = None,
explicit_init: bool = False,
**kwargs: Any
)
Bases: HyperPrimitive
A continuous value within a range.
Example::
# A float value between between 0.0 and 1.0. v = pg.floatv(0.0, 1.0)
See also:
Source code in pygx/symbolic/_object.py
2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 | |
on_sym_bound
¶
Constructor.
Source code in pygx/hyper/_numerical.py
dna_spec
¶
Returns corresponding DNASpec.
Source code in pygx/hyper/_numerical.py
encode
¶
encode(value: float) -> DNA
Encode a float value into a DNA.
Source code in pygx/hyper/_numerical.py
custom_apply
¶
custom_apply(
path: KeyPath,
value_spec: ValueSpec,
allow_partial: bool = False,
child_transform: None | Callable[[KeyPath, Field, Any], Any] = None,
) -> tuple[bool, Float]
Validate candidates during value_spec binding time.
Source code in pygx/hyper/_numerical.py
ObjectTemplate
¶
ObjectTemplate(
value: Any,
compute_derived: bool = False,
where: Callable[[HyperPrimitive], bool] | None = None,
)
Bases: HyperValue, Formattable
Object template that encodes and decodes symbolic values.
An object template can be created from a hyper value, which is a symbolic object with some parts placeheld by hyper primitives. For example::
x = A(a=0, b=pg.oneof(['foo', 'bar']), c=pg.manyof(2, [1, 2, 3, 4, 5, 6]), d=pg.floatv(0.1, 0.5), e=pg.oneof([ { 'f': pg.oneof([True, False]), } { 'g': pg.manyof(2, [B(), C(), D()], distinct=False), 'h': pg.manyof(2, [0, 1, 2], sorted=True), } ]) }) t = pg.template(x)
In this example, the root template have 4 children hyper primitives associated with keys 'b', 'c', 'd' and 'e', while the hyper primitive 'e' have 3 children associated with keys 'f', 'g' and 'h', creating a conditional search space.
Thus the DNA shape is determined by the definition of template, described by geno.DNASpec. In this case, the DNA spec of this template looks like::
pg.geno.space([ pg.geno.oneof([ # Spec for 'b'. pg.geno.constant(), # A constant template for 'foo'. pg.geno.constant(), # A constant template for 'bar'. ]), pg.geno.manyof([ # Spec for 'c'. pg.geno.constant(), # A constant template for 1. pg.geno.constant(), # A constant template for 2. pg.geno.constant(), # A constant template for 3. pg.geno.constant(), # A constant template for 4. pg.geno.constant(), # A constant template for 5. pg.geno.constant(), # A constant template for 6. ]), pg.geno.floatv(0.1, 0.5), # Spec for 'd'. pg.geno.oneof([ # Spec for 'e'. pg.geno.space([ pg.geno.oneof([ # Spec for 'f'. pg.geno.constant(), # A constant template for True. pg.geno.constant(), # A constant template for False. ]) ]), pg.geno.space([ pg.geno.manyof(2, [ # Spec for 'g'. pg.geno.constant(), # A constant template for B(). pg.geno.constant(), # A constant template for C(). pg.geno.constant(), # A constant template for D(). ], distinct=False) # choices of the same value can # be selected multiple times. pg.geno.manyof(2, [ # Spec for 'h'. pg.geno.constant(), # A constant template for 0. pg.geno.constant(), # A constant template for 1. pg.geno.constant(), # A constant template for 2. ], sorted=True) # acceptable choices needs to be sorted, # which enables using choices as set (of # possibly repeated values). ]) ])
It may generate DNA as the following
DNA([0, [0, 2], 0.1, (0, 0)])
A template can also work only on a subset of hyper primitives from the input
value through the where function. This is useful to partition a search space
into parts for separate optimization.
For example::
t = pg.hyper.ObjectTemplate( A(a=pg.oneof([1, 2]), b=pg.oneof([3, 4])), where=lambda e: e.root_path == 'a') assert t.dna_spec() == pg.geno.space([ pg.geno.oneof(location='a', candidates=[ pg.geno.constant(), # For a=1 pg.geno.constant(), # For a=2 ], literal_values=['(0/2) 1', '(½) 2']) ]) assert t.decode(pg.DNA(0)) == A(a=1, b=pg.oneof([3, 4]))
Constructor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
Value (maybe) annotated with generators to use as template. |
required |
compute_derived
|
bool
|
Whether to compute derived value at this level. We only want to compute derived value at root level since reference path may go out of scope of a non-root ObjectTemplate. |
False
|
where
|
Callable[[HyperPrimitive], bool] | None
|
Function to filter hyper primitives. If None, all hyper primitives
from |
None
|
Source code in pygx/hyper/_object_template.py
hyper_primitives
property
¶
hyper_primitives: list[tuple[str, HyperValue]]
Returns hyper primitives in tuple (relative path, hyper primitive).
dna_spec
¶
Return DNA spec (geno.Space) from this template.
Source code in pygx/hyper/_object_template.py
encode
¶
encode(value: Any) -> DNA
Encode a value into a DNA.
Example::
# DNA of a constant template: template = pg.hyper.ObjectTemplate({'a': 0}) assert template.encode({'a': 0}) == pg.DNA(None) # Raises: Unmatched value between template and input. template.encode({'a': 1})
# DNA of a template containing only one pg.oneof. template = pg.hyper.ObjectTemplate({'a': pg.oneof([1, 2])}) assert template.encode({'a': 1}) == pg.DNA(0)
# DNA of a template containing only one pg.oneof. template = pg.hyper.ObjectTemplate({'a': pg.floatv(0.1, 1.0)}) assert template.encode({'a': 0.5}) == pg.DNA(0.5)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
Value to encode. |
required |
Returns:
| Type | Description |
|---|---|
DNA
|
Encoded DNA. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in pygx/hyper/_object_template.py
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | |
try_encode
¶
try_encode(value: Any) -> tuple[bool, DNA | None]
Try to encode a value without raise Exception.
Source code in pygx/hyper/_object_template.py
format
¶
Format this object.
Source code in pygx/hyper/_object_template.py
custom_apply
¶
custom_apply(
path: KeyPath,
value_spec: ValueSpec,
allow_partial: bool,
child_transform: None | Callable[[KeyPath, Field, Any], Any] = None,
) -> tuple[bool, ObjectTemplate]
Validate candidates during value_spec binding time.
Source code in pygx/hyper/_object_template.py
manyof
¶
manyof(
k: int,
candidates: Iterable[Any],
distinct: bool = True,
sorted: bool = False,
*,
name: str | None = None,
hints: Any | None = None,
**kwargs: Any
) -> Any
N choose K.
Example::
class A(pg.Object): x: int
# Chooses 2 distinct candidates. v = pg.manyof(2, [1, 2, 3])
# Chooses 2 non-distinct candidates. v = pg.manyof(2, [1, 2, 3], distinct=False)
# Chooses 2 distinct candidates sorted by their indices. v = pg.manyof(2, [1, 2, 3], sorted=True)
# A complex type as candidate. v1 = pg.manyof(2, ['a', {'x': 1}, A(1)])
# A hierarchical categorical choice: v2 = pg.manyof(2, [ 'foo', 'bar', A(pg.oneof([1, 2, 3])) ])
.. note::
Under symbolic mode (by default), pg.manyof returns a pg.hyper.ManyOf
object. Under dynamic evaluation mode, which is called under the context of
pygx.hyper.DynamicEvaluationContext.collect or
pygx.hyper.DynamicEvaluationContext.apply, it evaluates to
a concrete candidate value.
To use conditional search space in dynamic evaluate mode, the candidate
should be wrapped with a lambda function, which is not necessary under
symbolic mode. For example::
pg.manyof(2, [
lambda: pg.oneof([0, 1], name='sub_a'),
lambda: pg.floatv(0.0, 1.0, name='sub_b'),
lambda: pg.manyof(2, ['a', 'b', 'c'], name='sub_c')
], name='root')
See also:
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k
|
int
|
number of choices to make. Should be no larger than the length of
|
required |
candidates
|
Iterable[Any]
|
Candidates to select from. Items of candidate can be any type, therefore it can have nested hyper primitives, which forms a hierarchical search space. |
required |
distinct
|
bool
|
If True, each choice needs to be unique. |
True
|
sorted
|
bool
|
If True, choices are sorted by their indices in the candidates. |
False
|
name
|
str | None
|
A name that can be used to identify a decision point in the search
space. This is needed when the code to instantiate the same hyper
primitive may be called multiple times under a
|
None
|
hints
|
Any | None
|
An optional value which acts as a hint for the controller. |
None
|
**kwargs
|
Any
|
Keyword arguments for backward compatibility.
|
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
In symbolic mode, this function returns a |
Any
|
In dynamic evaluate mode, this function returns a list of items in |
Any
|
|
Any
|
If evaluated under a |
Any
|
this function will return a list of selected candidates. |
Any
|
If evaluated under a |
Any
|
scope, it will return a list of the first valid combination from the |
Any
|
# Evaluates to [0, 1, 2]. manyof(3, range(5)) # Evaluates to [0, 0, 0]. manyof(3, range(5), distinct=False) |
Source code in pygx/hyper/_categorical.py
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 | |
oneof
¶
N choose 1.
Example::
class A(pg.Object): x: int
# A single categorical choice: v = pg.oneof([1, 2, 3])
# A complex type as candidate. v1 = pg.oneof(['a', {'x': 1}, A(1)])
# A hierarchical categorical choice: v2 = pg.oneof([ 'foo', 'bar', A(pg.oneof([1, 2, 3])) ])
See also:
.. note::
Under symbolic mode (by default), pg.oneof returns a pg.hyper.OneOf
object. Under dynamic evaluation mode, which is called under the context of
pygx.hyper.DynamicEvaluationContext.collect or
pygx.hyper.DynamicEvaluationContext.apply, it evaluates to
a concrete candidate value.
To use conditional search space in dynamic evaluation mode, the candidate
should be wrapped with a lambda function, which is not necessary under
symbolic mode. For example::
pg.oneof([lambda: pg.oneof([0, 1], name='sub'), 2], name='root')
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
candidates
|
Iterable[Any]
|
Candidates to select from. Items of candidate can be any type, therefore it can have nested hyper primitives, which forms a hierarchical search space. |
required |
name
|
str | None
|
A name that can be used to identify a decision point in the search
space. This is needed when the code to instantiate the same hyper
primitive may be called multiple times under a
|
None
|
hints
|
Any | None
|
An optional value which acts as a hint for the controller. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
In symbolic mode, this function returns a |
Any
|
In dynamic evaluation mode, this function returns one of the items in |
Any
|
|
Any
|
If evaluated under a |
Any
|
this function will return the selected candidate. |
Any
|
If evaluated under a |
Any
|
scope, it will return the first candidate. |
Source code in pygx/hyper/_categorical.py
permutate
¶
Permuatation of candidates.
Example::
class A(pg.Object): x: int
# Permutates the candidates. v = pg.permutate([1, 2, 3])
# A complex type as candidate. v1 = pg.permutate(['a', {'x': 1}, A(1)])
# A hierarchical categorical choice: v2 = pg.permutate([ 'foo', 'bar', A(pg.oneof([1, 2, 3])) ])
.. note::
Under symbolic mode (by default), pg.manyof returns a pg.hyper.ManyOf
object. Under dynamic evaluate mode, which is called under the context of
pygx.hyper.DynamicEvaluationContext.collect or
pygx.hyper.DynamicEvaluationContext.apply, it evaluates to
a concrete candidate value.
To use conditional search space in dynamic evaluate mode, the candidate
should be wrapped with a lambda function, which is not necessary under
symbolic mode. For example::
pg.permutate([
lambda: pg.oneof([0, 1], name='sub_a'),
lambda: pg.floatv(0.0, 1.0, name='sub_b'),
lambda: pg.manyof(2, ['a', 'b', 'c'], name='sub_c')
], name='root')
See also:
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
candidates
|
Iterable[Any]
|
Candidates to select from. Items of candidate can be any type, therefore it can have nested hyper primitives, which forms a hierarchical search space. |
required |
name
|
str | None
|
A name that can be used to identify a decision point in the search
space. This is needed when the code to instantiate the same hyper
primitive may be called multiple times under a
|
None
|
hints
|
Any | None
|
An optional value which acts as a hint for the controller. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
In symbolic mode, this function returns a |
Any
|
In dynamic evaluate mode, this function returns a permutation from |
Any
|
|
Any
|
If evaluated under an |
Any
|
this function will return a permutation of candidates based on controller |
Any
|
decisions. |
Any
|
If evaluated under a |
Any
|
scope, it will return the first valid permutation. |
Any
|
Source code in pygx/hyper/_categorical.py
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 | |
reference
¶
reference(reference_path: str) -> ValueReference
dynamic_evaluate
¶
dynamic_evaluate(
evaluate_fn: Callable[[HyperValue], Any] | None,
yield_value: Any = None,
exit_fn: Callable[[], None] | None = None,
per_thread: bool = True,
) -> Iterator[Any]
Eagerly evaluate hyper primitives within current scope.
Example::
global_indices = [0] def evaluate_fn(x: pg.hyper.HyperPrimitive): if isinstance(x, pg.hyper.OneOf): return x.candidates[global_indices[0]] raise NotImplementedError()
with pg.hyper.dynamic_evaluate(evaluate_fn): assert 0 = pg.oneof([0, 1, 2])
Please see pygx.DynamicEvaluationContext.apply as an example
for using this method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
evaluate_fn
|
Callable[[HyperValue], Any] | None
|
A callable object that evaluates a hyper value such as oneof, manyof, floatv, and etc. into a concrete value. |
required |
yield_value
|
Any
|
Value to yield return. |
None
|
exit_fn
|
Callable[[], None] | None
|
A callable object to be called when exiting the context scope. |
None
|
per_thread
|
bool
|
If True, the context manager will be applied to current thread only. Otherwise, it will be applied on current process. |
True
|
Yields:
| Type | Description |
|---|---|
Any
|
|
Source code in pygx/hyper/_dynamic_evaluation.py
trace
¶
trace(
fun: Callable[[], Any],
*,
where: Callable[[HyperPrimitive], bool] | None = None,
require_hyper_name: bool = False,
per_thread: bool = True
) -> DynamicEvaluationContext
Trace the hyper primitives called within a function by executing it.
See examples in pygx.hyper.DynamicEvaluationContext.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fun
|
Callable[[], Any]
|
Function in which the search space is defined. |
required |
where
|
Callable[[HyperPrimitive], bool] | None
|
A callable object that decide whether a hyper primitive should be
included when being instantiated under |
None
|
require_hyper_name
|
bool
|
If True, all hyper primitives defined in this scope will need to carry their names, which is usually a good idea when the function that instantiates the hyper primtives need to be called multiple times. |
False
|
per_thread
|
bool
|
If True, the context manager will be applied to current thread only. Otherwise, it will be applied on current process. |
True
|
Returns:
| Type | Description |
|---|---|
DynamicEvaluationContext
|
An DynamicEvaluationContext that can be passed to |
Source code in pygx/hyper/_dynamic_evaluation.py
evolve
¶
evolve(
initial_value: Symbolic,
node_transform: Callable[[KeyPath, Any, Symbolic], Any],
*,
weights: (
None | Callable[[MutationType, KeyPath, Any, Symbolic], float]
) = None,
name: str | None = None,
hints: Any | None = None
) -> Evolvable
An evolvable symbolic value.
Example::
@pg.symbolize @dataclasses.dataclass class Foo: x: int y: int
@pg.symbolize @dataclasses.dataclass class Bar: a: int b: int
# Defines possible transitions. def node_transform(location, value, parent): if isinstance(value, Foo) return Bar(value.x, value.y) if location.key == 'x': return random.choice([1, 2, 3]) if location.key == 'y': return random.choice([3, 4, 5])
v = pg.evolve(Foo(1, 3), node_transform)
See also:
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
initial_value
|
Symbolic
|
The initial value to evolve. |
required |
node_transform
|
Callable[[KeyPath, Any, Symbolic], Any]
|
A callable object that takes information of the value to
operate (e.g. location, old value, parent node) and returns a new value as
a replacement for the node. Such information allows users to not only
access the mutation node, but the entire symbolic tree if needed, allowing
complex mutation rules to be written with ease - for example - check
adjacent nodes while modifying a list element. This function is designed
to take care of both node replacements and node insertions. When insertion
happens, the old value for the location will be |
required |
weights
|
None | Callable[[MutationType, KeyPath, Any, Symbolic], float]
|
An optional callable object that returns the unnormalized (e.g. the sum of all probabilities don't have to sum to 1.0) mutation probabilities for all the nodes in the symbolic tree, based on (mutation type, location, old value, parent node), If None, all the locations and mutation types will be sampled uniformly. |
None
|
name
|
str | None
|
An optional name of the decision point. |
None
|
hints
|
Any | None
|
An optional hints for the decision point. |
None
|
Returns:
| Type | Description |
|---|---|
Evolvable
|
A |
Source code in pygx/hyper/_evolvable.py
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | |
iterate
¶
iterate(
hyper_value: Any,
num_examples: int | None = None,
algorithm: DNAGenerator | None = None,
where: Callable[[HyperPrimitive], bool] | None = None,
force_feedback: bool = False,
) -> Iterator[Any]
Iterate a hyper value based on an algorithm.
Example::
hyper_dict = pg.Dict(x=pg.oneof([1, 2, 3]), y=pg.oneof(['a', 'b']))
# Get all examples from the hyper_dict. assert list(pg.iter(hyper_dict)) == [ pg.Dict(x=1, y='a'), pg.Dict(x=1, y='b'), pg.Dict(x=2, y='a'), pg.Dict(x=2, y='b'), pg.Dict(x=3, y='a'), pg.Dict(x=3, y='b'), ]
# Get the first two examples. assert list(pg.iter(hyper_dict, 2)) == [ pg.Dict(x=1, y='a'), pg.Dict(x=1, y='b'), ]
# Random sample examples, which is equivalent to pg.random_sample.
list(pg.iter(hyper_dict, 2, pg.geno.Random()))
# Iterate examples with feedback loop. for d, feedback in pg.iter( hyper_dict, 10, pg.algo.evolution.regularized_evolution(pg.algo.evolution.mutators.Uniform())): feedback(d.x)
# Only materialize selected parts. assert list( pg.iter(hyper_dict, where=lambda x: len(x.candidates) == 2)) == [ pg.Dict(x=pg.oneof([1, 2, 3]), y='a'), pg.Dict(x=pg.oneof([1, 2, 3]), y='b'), ]
pg.iter distinguishes from pg.sample in that it's designed
for simple in-process iteration, which is handy for quickly generating
examples from algorithms without maintaining trail states. On the contrary,
pg.sample is designed for distributed sampling, with parallel workers and
failover handling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hyper_value
|
Any
|
A hyper value that represents a space of instances. |
required |
num_examples
|
int | None
|
An optional integer as the max number of examples to propose. If None, propose will return an iterator of infinite examples. |
None
|
algorithm
|
DNAGenerator | None
|
An optional DNA generator. If None, Sweeping will be used, which iterates examples in order. |
None
|
where
|
Callable[[HyperPrimitive], bool] | None
|
Function to filter hyper primitives. If None, all hyper primitives
from |
None
|
force_feedback
|
bool
|
If True, always return the Feedback object together
with the example, this is useful when the user want to pass different
DNAGenerators to |
False
|
Yields:
| Type | Description |
|---|---|
Any
|
A tuple of (example, feedback_fn) if the algorithm needs a feedback or |
Any
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
when |
Source code in pygx/hyper/_iter.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | |
random_sample
¶
random_sample(
value: Any,
num_examples: int | None = None,
where: Callable[[HyperPrimitive], bool] | None = None,
seed: int | None = None,
) -> Iterator[Any]
Returns an iterator of random sampled examples.
Example::
hyper_dict = pg.Dict(x=pg.oneof(range(3)), y=pg.floatv(0.0, 1.0))
# Generate one random example from the hyper_dict. d = next(pg.random_sample(hyper_dict))
# Generate 5 random examples with random seed. ds = list(pg.random_sample(hyper_dict, 5, seed=1))
# Generate 3 random examples of x with y intact.
ds = list(pg.random_sample(hyper_dict, 3,
where=lambda x: isinstance(x, pg.hyper.OneOf)))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
A (maybe) hyper value. |
required |
num_examples
|
int | None
|
An optional integer as number of examples to propose. If None, propose will return an iterator that iterates forever. |
None
|
where
|
Callable[[HyperPrimitive], bool] | None
|
Function to filter hyper primitives. If None, all hyper primitives in
|
None
|
seed
|
int | None
|
An optional integer as random seed. |
None
|
Returns:
| Type | Description |
|---|---|
Iterator[Any]
|
Iterator of random examples. |
Source code in pygx/hyper/_iter.py
floatv
¶
floatv(
min_value: float,
max_value: float,
scale: str | None = None,
*,
name: str | None = None,
hints: Any | None = None
) -> Any
A continuous value within a range.
Example::
# A continuous value within [0.0, 1.0] v = pg.floatv(0.0, 1.0)
See also:
.. note::
Under symbolic mode (by default), pg.floatv returns a pg.hyper.Float
object. Under dynamic evaluate mode, which is called under the context of
pygx.hyper.DynamicEvaluationContext.collect or
pygx.hyper.DynamicEvaluationContext.apply, it evaluates to
a concrete candidate value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
min_value
|
float
|
Minimum acceptable value (inclusive). |
required |
max_value
|
float
|
Maximum acceptable value (inclusive). |
required |
scale
|
str | None
|
An optional string as the scale of the range. Supported values
are None, 'linear', 'log', and 'rlog'.
If None, the feasible space is unscaled.
If |
None
|
name
|
str | None
|
A name that can be used to identify a decision point in the search
space. This is needed when the code to instantiate the same hyper
primitive may be called multiple times under a
|
None
|
hints
|
Any | None
|
An optional value which acts as a hint for the controller. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
In symbolic mode, this function returns a |
Any
|
In dynamic evaluate mode, this function returns a float value that is no |
Any
|
less than the |
Any
|
If evaluated under an |
Any
|
this function will return a chosen float value from the controller |
Any
|
decisions. |
Any
|
If evaluated under a |
Any
|
scope, it will return |
Source code in pygx/hyper/_numerical.py
dna_spec
¶
dna_spec(
value: Any, where: Callable[[HyperPrimitive], bool] | None = None
) -> DNASpec
Returns the DNASpec from a (maybe) hyper value.
Example::
hyper = pg.Dict(x=pg.oneof([1, 2, 3]), y=pg.oneof(['a', 'b'])) spec = pg.dna_spec(hyper)
assert spec.space_size == 6 assert len(spec.decision_points) == 2 print(spec.decision_points)
# Select a partial space with where argument.
spec = pg.dna_spec(hyper, where=lambda x: len(x.candidates) == 2)
assert spec.space_size == 2 assert len(spec.decision_points) == 1
See also:
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
A (maybe) hyper value. |
required |
where
|
Callable[[HyperPrimitive], bool] | None
|
Function to filter hyper primitives. If None, all hyper primitives
from |
None
|
Returns:
| Type | Description |
|---|---|
DNASpec
|
A DNASpec object, which represents the search space from algorithm's view. |
Source code in pygx/hyper/_object_template.py
materialize
¶
materialize(
value: Any,
parameters: DNA | dict[str, Any],
use_literal_values: bool = True,
where: Callable[[HyperPrimitive], bool] | None = None,
) -> Any
Materialize a (maybe) hyper value using a DNA or parameter dict.
Example::
hyper_dict = pg.Dict(x=pg.oneof(['a', 'b']), y=pg.floatv(0.0, 1.0))
# Materialize using DNA. assert pg.materialize( hyper_dict, pg.DNA([0, 0.5])) == pg.Dict(x='a', y=0.5)
# Materialize usign key value pairs.
# See pg.DNA.from_dict for more details.
assert pg.materialize(
hyper_dict, {'x': 0, 'y': 0.5}) == pg.Dict(x='a', y=0.5)
# Partially materialize. v = pg.materialize( hyper_dict, pg.DNA(0), where=lambda x: isinstance(x, pg.hyper.OneOf)) assert v == pg.Dict(x='a', y=pg.floatv(0.0, 1.0))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
A (maybe) hyper value |
required |
parameters
|
DNA | dict[str, Any]
|
A DNA object or a dict of string (key path) to a
string (in format of ' |
required |
use_literal_values
|
bool
|
Applicable when |
True
|
where
|
Callable[[HyperPrimitive], bool] | None
|
Function to filter hyper primitives. If None, all hyper primitives
from |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
A materialized value. |
Raises:
| Type | Description |
|---|---|
TypeError
|
if parameters is not a DNA or dict. |
ValueError
|
if parameters cannot be decoded. |
Source code in pygx/hyper/_object_template.py
template
¶
template(
value: Any, where: Callable[[HyperPrimitive], bool] | None = None
) -> ObjectTemplate
Creates an object template from the input.
Example::
d = pg.Dict(x=pg.oneof(['a', 'b', 'c'], y=pg.manyof(2, range(4)))) t = pg.template(d)
assert t.dna_spec() == pg.geno.space([ pg.geno.oneof([ pg.geno.constant(), pg.geno.constant(), pg.geno.constant(), ], location='x'), pg.geno.manyof([ pg.geno.constant(), pg.geno.constant(), pg.geno.constant(), pg.geno.constant(), ], location='y') ])
assert t.encode(pg.Dict(x='a', y=0)) == pg.DNA([0, 0]) assert t.decode(pg.DNA([0, 0])) == pg.Dict(x='a', y=0)
t = pg.template(d, where=lambda x: isinstance(x, pg.hyper.ManyOf)) assert t.dna_spec() == pg.geno.space([ pg.geno.manyof([ pg.geno.constant(), pg.geno.constant(), pg.geno.constant(), pg.geno.constant(), ], location='y') ]) assert t.encode(pg.Dict(x=pg.oneof(['a', 'b', 'c']), y=0)) == pg.DNA(0) assert t.decode(pg.DNA(0)) == pg.Dict(x=pg.oneof(['a', 'b', 'c']), y=0)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
A value based on which the template is created. |
required |
where
|
Callable[[HyperPrimitive], bool] | None
|
Function to filter hyper values. If None, all hyper primitives from
|
None
|
Returns:
| Type | Description |
|---|---|
ObjectTemplate
|
A template object. |
Source code in pygx/hyper/_object_template.py
options: show_root_heading: false show_root_toc_entry: false members_order: source heading_level: 2