Optimizers API¶
AID2E Optimizers module - Bayesian and evolutionary algorithms.
This module provides various optimization algorithms for multi-objective optimization problems, including:
- BaseOptimizer: Abstract base class defining the common optimizer interface.
- AxOptimizer: Bayesian optimization using Ax with Sobol initialization, SAASBO surrogate model, and qNEHVI acquisition function.
- PyMOOProblem: PyMOO-only public
Problemwrapper for structural ask/tell integrations. Ax does not expose an equivalent public problem wrapper. - PyMOOOptimizer: Evolutionary optimization (GA, NSGA-II, NSGA-III, MOEA/D) via PyMOO's ask/tell interface for external evaluation.
- compute_pareto_front: Backend-agnostic Pareto front utility.
Attributes:
| Name | Type | Description |
|---|---|---|
__version__ |
Version string inherited from the main aid2e package. |
AID2EProblem
¶
Bases: PyMOOProblem
Deprecated compatibility alias for PyMOOProblem.
Source code in src/aid2e/optimizers/pymoo/optimizer.py
161 162 163 164 165 166 167 168 169 170 171 172 173 | |
__init__(*args, **kwargs)
¶
Warn and delegate to PyMOOProblem.
Source code in src/aid2e/optimizers/pymoo/optimizer.py
164 165 166 167 168 169 170 171 172 173 | |
AxOptimizer
¶
Bases: BaseOptimizer
Ax-based Bayesian optimization for multi-objective optimization.
This optimizer uses the Ax platform for Bayesian optimization with support for multiple objectives and native Ax Modular BoTorch generation.
Attributes:
| Name | Type | Description |
|---|---|---|
config |
AxOptimizerConfig instance with strategy settings. |
|
objective_names |
List[str]
|
List of objective metric names. |
experiment |
Ax Experiment object managing trials. |
|
generation_strategy |
Ax GenerationStrategy for candidate generation. |
Examples:
>>> from aid2e.optimizers.ax import AxOptimizer, AxOptimizerConfig
>>> search_space = SearchSpace(
... parameters={
... "x": {"type": "range", "bounds": [0.0, 1.0]},
... "y": {"type": "range", "bounds": [0.0, 1.0]}
... }
... )
>>> config = AxOptimizerConfig(
... initialization_strategy="sobol",
... generator="BOTORCH_MODULAR"
... )
>>> optimizer = AxOptimizer(
... search_space=search_space,
... config=config,
... objective_names=["loss", "time"]
... )
Notes
This implementation defaults to a native Ax node-based generation
strategy that transitions from an initializer node into
Generators.BOTORCH_MODULAR.
Project: AID2E v0.0.1 - AI assisted Detector Design for EIC Homepage: https://aid2e.github.io/AID2E-framework Repository: https://github.com/aid2e/AID2E-framework.git
Source code in src/aid2e/optimizers/ax/optimizer.py
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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 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 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 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 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 728 729 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 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 | |
__init__(search_space, config, objective_names, seed=None, objective_directions=None)
¶
Initialize the Ax optimizer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
search_space
|
Union[SearchSpace, DesignConfig]
|
Parameter search space definition. |
required |
config
|
AxOptimizerConfig
|
AxOptimizerConfig instance with strategy settings. |
required |
objective_names
|
List[str]
|
List of objective metric names to optimize. |
required |
seed
|
Optional[int]
|
Random seed for reproducibility (overrides config.seed if provided). |
None
|
Raises:
| Type | Description |
|---|---|
ImportError
|
If Ax is not installed. |
ValueError
|
If search_space is empty or config is invalid. |
Notes
The optimizer is initialized but not yet ready to suggest candidates. Ax Experiment and GenerationStrategy are created lazily on first use.
Source code in src/aid2e/optimizers/ax/optimizer.py
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | |
__repr__()
¶
Return string representation of the optimizer.
Returns:
| Type | Description |
|---|---|
str
|
String describing the optimizer configuration. |
Source code in src/aid2e/optimizers/ax/optimizer.py
960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 | |
load_state(state)
¶
Load optimizer state from serialized form.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
Dict[str, Any]
|
Dictionary containing serialized optimizer state. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If state is invalid or incompatible. |
Notes
This recreates the Ax experiment and generation strategy, then replays all trials to restore the optimizer state.
Source code in src/aid2e/optimizers/ax/optimizer.py
884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 | |
mark_trial_failed(trial_index, *, parameters=None, reason=None)
¶
Mark a failed evaluation in AID2E and the Ax experiment.
Source code in src/aid2e/optimizers/ax/optimizer.py
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 | |
serialize_state()
¶
Serialize optimizer state for distributed execution.
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
Dictionary containing all necessary state to reconstruct the optimizer. |
Examples:
>>> state = optimizer.serialize_state()
>>> json.dumps(state) # Should be JSON-serializable
Source code in src/aid2e/optimizers/ax/optimizer.py
828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 | |
suggest_candidates(n_candidates=1)
¶
Suggest the next batch of parameter configurations to evaluate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_candidates
|
int
|
Number of candidates to generate. |
1
|
Returns:
| Type | Description |
|---|---|
List[Dict[str, Any]]
|
List of parameter dictionaries ready for evaluation. |
Notes
Constraints are handled natively by Ax when present in search_space. Ax enforces constraints during candidate generation automatically.
IMPLEMENTATION NOTE: This method generates the requested batch in a
single Ax call whenever possible, then splits the resulting batch
into individual AID2E trial records so the rest of the framework can
keep using single-trial update_with_results semantics.
The GenerationStrategy still properly tracks progress: after n_initial_samples individual trials complete (regardless of how they were generated), it automatically switches from Sobol to BO.
Source code in src/aid2e/optimizers/ax/optimizer.py
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 728 729 730 731 732 733 734 735 736 737 738 | |
update_with_results(trial_index, parameters, metrics)
¶
Update optimizer with evaluation results from a trial.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trial_index
|
int
|
Unique identifier for the trial. |
required |
parameters
|
Dict[str, Any]
|
Parameter values that were evaluated. |
required |
metrics
|
Dict[str, float]
|
Objective values obtained from evaluation. |
required |
Examples:
>>> optimizer.update_with_results(
... trial_index=0,
... parameters={'x': 0.5, 'y': 0.3},
... metrics={'loss': 0.1, 'accuracy': 0.9}
... )
Notes
Completes the trial in Ax experiment and attaches data. This allows the surrogate model to learn from the evaluation.
Source code in src/aid2e/optimizers/ax/optimizer.py
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 | |
AxOptimizerConfig
¶
Bases: BaseModel
Configure the Ax optimizer backend for AID2E.
Define the tuning parameters used by the Ax-based Bayesian optimization workflow, including initialization behavior, model-generation settings, and core iteration controls.
Attributes:
| Name | Type | Description |
|---|---|---|
initialization_strategy |
Literal['sobol', 'uniform', 'center']
|
Choose how the initial design points are drawn
before model-based generation begins. Supported values are
|
generator |
str
|
Specify the Ax generator enum name used for model-based
candidate generation. The default is |
generator_kwargs |
dict[str, Any]
|
Provide keyword arguments for Ax |
generator_gen_kwargs |
dict[str, Any]
|
Provide generation-time keyword arguments passed
into Ax candidate generation (for example,
|
objective_thresholds |
Optional[dict[str, float]]
|
Optionally map objective metric names to threshold values for multi-objective optimization. |
n_initial_samples |
int
|
Set the number of initialization trials. |
n_iterations |
int
|
Set the total optimization iteration budget. |
batch_size |
int
|
Set the number of candidates proposed per iteration. |
seed |
Optional[int]
|
Set an optional random seed for reproducibility. |
Examples:
>>> config = AxOptimizerConfig(
... initialization_strategy="sobol",
... generator="BOTORCH_MODULAR",
... generator_kwargs={"fit_out_of_design": False},
... generator_gen_kwargs={"model_gen_options": {"acqf_optimizer_kwargs": {"num_restarts": 8}}},
... n_initial_samples=12,
... n_iterations=60,
... batch_size=2,
... seed=42,
... )
>>> config.generator
'BOTORCH_MODULAR'
Notes
Legacy fields such as surrogate_model and
acquisition_function are explicitly rejected.
Source code in src/aid2e/optimizers/ax/config.py
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 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 | |
normalize_generator(value)
classmethod
¶
Normalize the configured generator to an Ax enum-style name.
Source code in src/aid2e/optimizers/ax/config.py
137 138 139 140 141 | |
reject_legacy_fields(raw_value)
classmethod
¶
Fail fast on the retired Ax config surface.
Source code in src/aid2e/optimizers/ax/config.py
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | |
BaseOptimizer
¶
Bases: ABC
Abstract base class for all AID2E optimizers.
Subclasses must implement the abstract methods to suggest candidates, ingest evaluation results, and surface optimizer state. The interface is intentionally minimal to support a range of backends (Ax, genetic algorithms, grid search) while keeping a consistent contract for the rest of the framework.
Concrete default implementations are provided for get_pareto_front and
get_best_trial using :func:compute_pareto_front. Individual backends
may override these when native support (e.g. PyMOO's built-in Pareto tools)
is preferable.
Source code in src/aid2e/optimizers/base.py
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 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 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 728 729 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 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 | |
n_objectives
property
¶
Return the number of optimisation objectives.
Returns:
| Type | Description |
|---|---|
int
|
Integer count derived from |
__init__(search_space, objective_names, seed=None, objective_directions=None)
¶
Initialize the optimizer with a search space and objective specification.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
search_space
|
Union[SearchSpace, DesignConfig]
|
Typed search space or DesignConfig to optimize over. |
required |
objective_names
|
List[str]
|
Ordered list of objective metric names. Each name
must match the keys returned in the |
required |
seed
|
Optional[int]
|
Optional integer seed for reproducibility. |
None
|
objective_directions
|
Optional[Dict[str, Any]]
|
Optional mapping from objective name to
|
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the search space is empty or no objective names are provided. |
Source code in src/aid2e/optimizers/base.py
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 | |
__repr__()
¶
Return string representation of the optimizer.
Returns:
| Type | Description |
|---|---|
str
|
String describing the optimizer configuration. |
Source code in src/aid2e/optimizers/base.py
820 821 822 823 824 825 826 827 828 829 830 831 832 | |
get_best_trial()
¶
Get the best trial found so far.
For single-objective optimisation, returns the completed trial with the
best metric value under its configured direction. For multi-objective,
returns the first trial from the Pareto front (arbitrary representative;
use :meth:get_pareto_front for the full front).
Returns:
| Type | Description |
|---|---|
Optional[Trial]
|
Best Trial, or |
Examples:
>>> best = optimizer.get_best_trial()
>>> if best:
... print(f"Best parameters: {best.parameters}")
... print(f"Best metrics: {best.metrics}")
Source code in src/aid2e/optimizers/base.py
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 | |
get_optimization_results(errors_by_trial=None)
¶
Return a normalized optimization-results payload.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
errors_by_trial
|
Optional[Dict[int, Dict[str, float]]]
|
Optional uncertainty/error fields keyed by trial index. |
None
|
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
Dictionary containing objective names and trial records with |
Dict[str, Any]
|
parameters, metrics, and both raw and display status labels. |
Source code in src/aid2e/optimizers/base.py
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 | |
get_pareto_front()
¶
Retrieve the current Pareto front of non-dominated solutions.
The default implementation delegates to :func:compute_pareto_front,
which operates on the trials returned by :meth:get_trials. Backends
with native Pareto support (e.g. PyMOO) may override this method to
expose more detailed Pareto metadata.
Returns:
| Type | Description |
|---|---|
List[Trial]
|
List of Trial objects representing Pareto-optimal solutions. |
List[Trial]
|
For single-objective optimisation, returns the single trial with |
List[Trial]
|
the best metric value under its configured direction. Returns an |
List[Trial]
|
empty list when no completed trials are available. |
Examples:
>>> pareto_front = optimizer.get_pareto_front()
>>> for trial in pareto_front:
... print(f"Params: {trial.parameters}, Metrics: {trial.metrics}")
Notes
Objective directions are read from self.objective_directions.
Source code in src/aid2e/optimizers/base.py
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 | |
get_trials()
¶
Return all recorded trials (pending, completed, and failed).
The base implementation reads directly from self._trials, which is
owned by BaseOptimizer and kept up to date by every backend.
Backends that maintain additional internal state may override this to
include synthetic or reconstructed trials, but doing so is uncommon.
Returns:
| Type | Description |
|---|---|
List[Trial]
|
List of non- |
Examples:
>>> done = [t for t in optimizer.get_trials() if t.status == "completed"]
Source code in src/aid2e/optimizers/base.py
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 | |
load_state(state)
abstractmethod
¶
Load optimizer state from serialized form.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
Dict[str, Any]
|
Dictionary containing serialized optimizer state, as returned by serialize_state(). |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If state is invalid or incompatible. |
Examples:
>>> import json
>>> with open('optimizer_state.json', 'r') as f:
... state = json.load(f)
>>> optimizer.load_state(state)
Notes
After loading state, the optimizer should be able to continue optimization as if it never stopped.
Source code in src/aid2e/optimizers/base.py
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 | |
mark_trial_failed(trial_index, *, parameters=None, reason=None)
¶
Record a failed evaluation without objective values.
Source code in src/aid2e/optimizers/base.py
553 554 555 556 557 558 559 560 561 562 563 564 565 566 | |
save_optimization_results(output_path, *, errors_by_trial=None)
¶
Write optimization results to disk as pretty-printed JSON.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output_path
|
Union[str, Path]
|
Directory where optimizer result files are written. |
required |
errors_by_trial
|
Optional[Dict[int, Dict[str, float]]]
|
Optional uncertainty/error fields keyed by trial index. |
None
|
Returns:
| Type | Description |
|---|---|
Dict[str, Path]
|
Paths of the written result files. |
Source code in src/aid2e/optimizers/base.py
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 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 | |
seed_from_trials(trials, *, only_completed=True)
¶
Inject external trials into the optimizer history without advancing the algorithm.
This is the backend-switch primitive. It lets you:
- Seed a new optimizer with results from a previous one (e.g. random init → MOEA → BO transition).
- Inject prior knowledge before the first
suggest_candidatescall. - Resume an optimisation from a checkpoint produced by a different backend.
Trials are appended to the internal _trials list with freshly
assigned sequential indices (starting from the current
_trial_counter). The original trial.index values from the
source optimizer are preserved in each trial's metadata under the
key "source_index".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trials
|
List[Trial]
|
Iterable of Trial objects to inject. The list may contain
|
required |
only_completed
|
bool
|
When |
True
|
Returns:
| Type | Description |
|---|---|
int
|
Number of trials actually injected. |
Examples:
>>> # Transfer best results from a random-search warmup:
>>> warmup_trials = random_opt.get_trials()
>>> pymoo_opt.seed_from_trials(warmup_trials)
100
>>> # Now start MOEA generation — the history already has 100 points
>>> candidates = pymoo_opt.suggest_candidates()
Notes
- This method does NOT advance PyMOO's (or any other backend's) internal population. The injected trials are purely visible in the history for Pareto-front and best-trial queries.
- Backends that want to warm-start their internal state from these trials should override this method.
Source code in src/aid2e/optimizers/base.py
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 | |
serialize_state()
abstractmethod
¶
Serialize optimizer state for distributed execution or checkpointing.
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
Dictionary containing all necessary state to reconstruct |
Dict[str, Any]
|
the optimizer. Should be JSON-serializable. |
Examples:
>>> state = optimizer.serialize_state()
>>> import json
>>> with open('optimizer_state.json', 'w') as f:
... json.dump(state, f)
Notes
This is crucial for distributed optimization where optimizer state needs to be shared across workers or checkpointed.
Source code in src/aid2e/optimizers/base.py
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 | |
set_trial_status(trial_index, status, *, parameters=None, metrics=None, metadata=None)
¶
Create or update a trial entry with a new lifecycle status.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trial_index
|
int
|
Unique trial identifier. |
required |
status
|
str
|
Trial lifecycle status (for example |
required |
parameters
|
Optional[Dict[str, Any]]
|
Optional parameter dictionary to store on the trial. |
None
|
metrics
|
Optional[Dict[str, float]]
|
Optional objective dictionary to store on the trial. |
None
|
metadata
|
Optional[Dict[str, Any]]
|
Optional metadata to merge into existing metadata. |
None
|
Returns:
| Type | Description |
|---|---|
Trial
|
The updated Trial object. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/aid2e/optimizers/base.py
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | |
suggest_candidates(n_candidates=1)
abstractmethod
¶
Suggest next parameter configurations to evaluate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_candidates
|
int
|
Number of candidates to suggest. |
1
|
Returns:
| Type | Description |
|---|---|
List[Dict[str, Any]]
|
List of parameter dictionaries, where each dictionary maps |
List[Dict[str, Any]]
|
parameter names to their suggested values. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If optimizer is not properly initialized. |
Examples:
>>> candidates = optimizer.suggest_candidates(n_candidates=5)
>>> candidates[0]
{'x': 0.5, 'y': 0.3, 'z': 2.1}
Notes
The implementation should use the configured strategy (e.g., Sobol sampling, Bayesian optimization, genetic algorithms).
Source code in src/aid2e/optimizers/base.py
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | |
update_with_results(trial_index, parameters, metrics)
abstractmethod
¶
Update optimizer with evaluation results from a trial.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trial_index
|
int
|
Unique identifier for the trial. |
required |
parameters
|
Dict[str, Any]
|
Parameter values that were evaluated. |
required |
metrics
|
Dict[str, float]
|
Objective values obtained from evaluation. Keys are metric names, values are metric values. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If metrics don't match expected objectives. |
Examples:
>>> optimizer.update_with_results(
... trial_index=0,
... parameters={'x': 0.5, 'y': 0.3},
... metrics={'loss': 0.1, 'accuracy': 0.9}
... )
Notes
After updating, the optimizer can use this information to suggest better candidates in subsequent calls to suggest_candidates().
Source code in src/aid2e/optimizers/base.py
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | |
PyMOOOptimizer
¶
Bases: BaseOptimizer
Evolutionary optimizer backed by PyMOO algorithms.
Implements the BaseOptimizer interface using PyMOO's ask/tell protocol
so that evaluations can be performed externally (e.g. via schedulers or
simulation jobs) without blocking PyMOO's internal loop.
The generation lifecycle is::
candidates = optimizer.suggest_candidates() # calls algorithm.ask()
for i, c in enumerate(candidates):
metrics = my_evaluate(c)
optimizer.update_with_results(i, c, metrics)
# After the last call above, algorithm.tell() is invoked automatically.
# The next suggest_candidates() call produces the next generation.
Supported algorithms
"ga"— Genetic Algorithm for single-objective optimisation."nsga2"— NSGA-II, recommended for 2–3 objectives."nsga3"— NSGA-III, recommended for 3+ objectives."moead"— MOEA/D, weight-decomposition approach.
Attributes:
| Name | Type | Description |
|---|---|---|
config |
|
|
n_gen_completed |
int
|
Number of generations that have been fully evaluated. |
Examples:
>>> from aid2e.optimizers.pymoo import PyMOOOptimizer, PyMOOOptimizerConfig
>>> from aid2e.optimizers.base import SearchSpace
>>> space = SearchSpace(
... parameters={
... "x": {"type": "range", "bounds": [0.0, 1.0]},
... "y": {"type": "range", "bounds": [0.0, 1.0]},
... }
... )
>>> config = PyMOOOptimizerConfig(pop_size=20, seed=0)
>>> opt = PyMOOOptimizer(space, config, objective_names=["loss"])
>>> candidates = opt.suggest_candidates()
>>> for trial_idx, c in enumerate(candidates):
... opt.update_with_results(trial_idx, c, {"loss": c["x"] + c["y"]})
>>> best = opt.get_best_trial()
Notes
- Objective directions are translated to PyMOO's minimization convention.
- Linear parameter constraints are not yet forwarded to PyMOO. A warning is emitted when the search space contains constraints.
n_candidatespassed tosuggest_candidatesis informational only; the actual batch size is determined by the algorithm (pop_sizefor the first generation,n_offspringsthereafter).
Project: AID2E v0.0.0 — AI assisted Detector Design for EIC Homepage: https://aid2e.github.io/AID2E-framework Repository: https://github.com/aid2e/AID2E-framework.git
Source code in src/aid2e/optimizers/pymoo/optimizer.py
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 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 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 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 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 728 729 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 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 | |
__init__(search_space, config, objective_names, seed=None, objective_directions=None)
¶
Initialise the PyMOO optimizer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
search_space
|
Union[SearchSpace, DesignConfig]
|
Parameter search space or a |
required |
config
|
PyMOOOptimizerConfig
|
|
required |
objective_names
|
List[str]
|
Ordered list of objective metric names. These must
match keys in the |
required |
seed
|
Optional[int]
|
Integer seed overriding |
None
|
objective_directions
|
Optional[Dict[str, Any]]
|
Optimization direction for each objective. |
None
|
Raises:
| Type | Description |
|---|---|
ImportError
|
If PyMOO is not installed. |
ValueError
|
If the search space is empty or |
Notes
The algorithm is initialised lazily; the actual PyMOO Problem
and Algorithm objects are created here but no evaluations occur
until suggest_candidates is called.
Source code in src/aid2e/optimizers/pymoo/optimizer.py
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 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | |
__repr__()
¶
Return a concise string representation of the optimizer.
Returns:
| Type | Description |
|---|---|
str
|
Human-readable description including algorithm, parameter count, |
str
|
objective count, and seed. |
Source code in src/aid2e/optimizers/pymoo/optimizer.py
944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 | |
load_state(state)
¶
Restore optimizer state from a serialised dictionary.
The search space, config, objective names, completed trials, and
(when available) the pickled algorithm state are all restored. If
algorithm_pickle is absent or cannot be deserialised, the algorithm
is rebuilt from the config and seed, which means the internal
population will be reset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
Dict[str, Any]
|
Dictionary as returned by |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If required keys are missing from |
ImportError
|
If PyMOO is not installed. |
Notes
After a successful load, suggest_candidates resumes from where
optimisation left off (provided the algorithm pickle was valid).
Any in-flight generation (partial results) is discarded on load.
Source code in src/aid2e/optimizers/pymoo/optimizer.py
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 | |
mark_trial_failed(trial_index, *, parameters=None, reason=None)
¶
Record a failed candidate and allow its generation to finish.
Source code in src/aid2e/optimizers/pymoo/optimizer.py
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 | |
seed_from_trials(trials, *, only_completed=True)
¶
Inject completed trials from an external source into the history.
Extends the base implementation with a guard that prevents seeding
while a generation is in-flight (i.e., suggest_candidates has
been called but not all update_with_results calls have come back).
The injected trials are recorded in the optimizer's history and
visible via get_trials() and get_pareto_front(). They do
not advance PyMOO's internal population — the next
suggest_candidates call still produces the next generation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trials
|
List[Trial]
|
Trials to inject, typically from a previous backend (e.g. random-initialisation results). |
required |
only_completed
|
bool
|
When |
True
|
Returns:
| Type | Description |
|---|---|
int
|
Number of trials actually injected. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If a generation is currently in-flight. |
Examples:
>>> n = pymoo_opt.seed_from_trials(random_opt.get_trials())
>>> print(f"Seeded {n} prior evaluations")
>>> candidates = pymoo_opt.suggest_candidates() # gen 1 starts
Source code in src/aid2e/optimizers/pymoo/optimizer.py
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 | |
serialize_state()
¶
Serialise optimizer state to a JSON-compatible dictionary.
The serialised state includes the config, search space description,
objective names, and all recorded trials. The PyMOO algorithm's
internal population state is serialised via pickle and encoded as
a base-64 string to allow full resumption without re-running
evaluations.
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
JSON-serialisable dictionary containing all state needed to |
Dict[str, Any]
|
rebuild this optimizer via |
Examples:
>>> import json
>>> state = optimizer.serialize_state()
>>> with open("checkpoint.json", "w") as f:
... json.dump(state, f)
Notes
If the algorithm cannot be pickled (rare), the "algorithm_pickle"
key is omitted and a WARNING is logged. load_state will then
recreate the algorithm from the config + seed instead.
Source code in src/aid2e/optimizers/pymoo/optimizer.py
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 | |
suggest_candidates(n_candidates=1)
¶
Suggest the next batch of candidates to evaluate.
Calls algorithm.ask() to retrieve the current generation population
from PyMOO and returns them as a list of parameter dicts. The actual
number of candidates is determined by the algorithm (pop_size for
the initial generation, n_offsprings thereafter), not by
n_candidates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_candidates
|
int
|
Advisory hint only. A |
1
|
Returns:
| Type | Description |
|---|---|
List[Dict[str, Any]]
|
List of parameter dicts, one per individual in the current |
List[Dict[str, Any]]
|
generation. Trial indices for these candidates begin at the |
List[Dict[str, Any]]
|
current |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If a previous generation has not yet been fully
evaluated (i.e. some |
Examples:
>>> candidates = optimizer.suggest_candidates()
>>> len(candidates)
100 # pop_size
Source code in src/aid2e/optimizers/pymoo/optimizer.py
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 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 | |
update_with_results(trial_index, parameters, metrics)
¶
Record evaluation results for one candidate and advance the algorithm.
When the last outstanding candidate of the current generation is
updated, the generation buffer is flushed automatically via
algorithm.tell().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trial_index
|
int
|
Index as returned in |
required |
parameters
|
Dict[str, Any]
|
Parameter values that were evaluated (used for bookkeeping; the underlying search point is already tracked). |
required |
metrics
|
Dict[str, float]
|
Objective values keyed by objective name. All names
listed in |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If any required objective is missing from |
Examples:
>>> optimizer.update_with_results(
... trial_index=0,
... parameters={"x": 0.5, "y": 0.3},
... metrics={"f1": 0.1, "f2": 0.9},
... )
Source code in src/aid2e/optimizers/pymoo/optimizer.py
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 | |
PyMOOOptimizerConfig
¶
Bases: BaseModel
Configuration for PyMOO-based evolutionary optimizers.
Attributes:
| Name | Type | Description |
|---|---|---|
algorithm |
Optional[PyMOOAlgorithm]
|
Optional evolutionary algorithm identifier. If omitted,
AID2E infers |
pop_size |
int
|
Population size (number of individuals per generation). |
n_offsprings |
Optional[int]
|
Number of offspring generated each generation. |
crossover_prob |
float
|
Simulated Binary Crossover (SBX) probability. |
crossover_eta |
float
|
SBX distribution index — larger values produce offspring closer to the parents. |
mutation_eta |
float
|
Polynomial mutation distribution index. |
n_iterations |
int
|
Number of generations to run when using this config in declarative/runtime-driven flows. |
n_partitions |
int
|
Reference-direction partitions for NSGA-III and MOEA/D.
The total number of reference directions grows combinatorially with
this value and |
seed |
Optional[int]
|
Random seed for reproducibility. |
verbose |
bool
|
Whether PyMOO prints per-generation progress to stdout. |
Examples:
>>> config = PyMOOOptimizerConfig(
... pop_size=100,
... seed=42,
... )
>>> config.algorithm is None
True
>>> config2 = PyMOOOptimizerConfig(algorithm="nsga3", n_partitions=12)
Notes
gais the recommended default for single-objective problems.- NSGA-II is the recommended default for 2-objective problems.
- For 3+ objectives consider NSGA-III or MOEA/D — their reference direction structures are better suited to high-dimensional fronts.
n_partitionshas a strong effect on runtime for NSGA-III/MOEA/D; start with 12 for 2-3 objectives and reduce for 4+ objectives.
Source code in src/aid2e/optimizers/pymoo/config.py
27 28 29 30 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 147 148 149 150 151 152 153 154 155 156 157 | |
resolve_algorithm(n_objectives)
¶
Resolve the algorithm for the given objective count.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_objectives
|
int
|
Number of objectives in the optimization problem. |
required |
Returns:
| Type | Description |
|---|---|
PyMOOAlgorithm
|
Concrete PyMOO algorithm identifier. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the configured explicit algorithm is incompatible with the objective count. |
Source code in src/aid2e/optimizers/pymoo/config.py
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | |
PyMOOProblem
¶
Bases: Problem
PyMOO Problem that wraps an AID2E SearchSpace.
This problem is structural-only for ask/tell workflows. ``decode_x``
translates PyMOO float vectors into
human-readable AID2E parameter dicts — the same representation returned
by suggest_candidates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_var
|
int
|
Number of continuous decision variables. |
required |
n_obj
|
int
|
Number of objectives. |
required |
xl
|
ndarray
|
Lower-bound array of shape |
required |
xu
|
ndarray
|
Upper-bound array of shape |
required |
param_items
|
List[Tuple[str, Any]]
|
Ordered list of |
required |
objective_names
|
List[str]
|
Ordered objective names. |
required |
Source code in src/aid2e/optimizers/pymoo/optimizer.py
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 147 148 149 150 151 152 153 154 155 156 157 158 | |
__init__(n_var, n_obj, xl, xu, param_items, objective_names)
¶
Initialise the PyMOO problem with search-space metadata.
Source code in src/aid2e/optimizers/pymoo/optimizer.py
106 107 108 109 110 111 112 113 114 115 116 117 118 | |
decode_x(x_row)
¶
Translate a PyMOO float vector into an AID2E parameter dictionary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x_row
|
ndarray
|
1-D float array of length |
required |
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
Mapping of parameter names to decoded values ( |
Dict[str, Any]
|
|
Source code in src/aid2e/optimizers/pymoo/optimizer.py
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | |
SearchSpace
dataclass
¶
Represent an optimization search space built from design parameters.
Attributes:
| Name | Type | Description |
|---|---|---|
parameters |
Dict[str, BaseParameter]
|
Mapping of parameter names to typed design parameters. |
constraints |
List[ParameterConstraint]
|
Optional list of parameter constraints to enforce. |
name |
Optional[str]
|
Optional identifier for the search space. |
source_config |
Optional[DesignConfig]
|
Optional originating DesignConfig for traceability. |
Examples:
>>> from aid2e.utilities.configurations.base_models import RangeParameter
>>> params = {
... "x": RangeParameter(name="x", value=0.5, bounds=(0.0, 1.0)),
... }
>>> space = SearchSpace(parameters=params)
>>> space.validate({"x": 0.4})
(True, [])
Source code in src/aid2e/optimizers/base.py
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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
__post_init__()
¶
Normalize parameter and constraint inputs after initialization.
Source code in src/aid2e/optimizers/base.py
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 | |
from_design_config(design_config)
classmethod
¶
Build a search space from a DesignConfig instance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
design_config
|
DesignConfig
|
Fully validated design configuration containing parameters and optional parameter constraints. |
required |
Returns:
| Type | Description |
|---|---|
SearchSpace
|
SearchSpace populated with flattened parameters and constraints. |
Source code in src/aid2e/optimizers/base.py
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | |
validate(param_values)
¶
Check if parameter values satisfy all constraints (for non-Ax optimizers).
This method is for optimizers that DON'T have native constraint support (e.g., random search, simple evolutionary algorithms). For optimizers with native constraint support (e.g., Ax), pass self.constraints directly to the optimizer instead of calling this method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
param_values
|
Dict[str, Any]
|
Mapping of qualified parameter names to concrete values. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
Tuple of |
List[str]
|
|
Tuple[bool, List[str]]
|
lists the names (or error strings) of failing constraints. |
Example
For optimizers WITHOUT constraint support¶
is_valid, failures = search_space.validate(candidate) if not is_valid: ... print(f"Constraint violations: {failures}")
For Ax (HAS constraint support) - DON'T use this method¶
Instead, pass search_space.constraints to Ax optimizer¶
Notes
- Only use this for runtime checking with constraint-agnostic optimizers
- Ax and similar optimizers handle constraints internally via self.constraints
- Syntax validation already done at DesignConfig load time
Source code in src/aid2e/optimizers/base.py
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
Trial
dataclass
¶
Capture the parameters and results of a single optimization trial.
Attributes:
| Name | Type | Description |
|---|---|---|
index |
int
|
Unique trial identifier within the optimizer. |
parameters |
Dict[str, Any]
|
Parameter values evaluated during the trial. |
metrics |
Optional[Dict[str, float]]
|
Objective values produced by evaluation (if available). |
metadata |
Dict[str, Any]
|
Optional auxiliary metadata about the trial. |
status |
str
|
Lifecycle status such as |
Examples:
>>> trial = Trial(
... index=0,
... parameters={"x": 0.5},
... metrics={"loss": 0.1},
... status="completed",
... )
>>> trial.metadata
{}
Source code in src/aid2e/optimizers/base.py
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 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 | |
__post_init__()
¶
Normalize metadata and status values after initialization.
Source code in src/aid2e/optimizers/base.py
221 222 223 224 225 226 227 228 229 230 231 | |
save_to_json(output_path)
¶
Write the trial's design parameters to disk as pretty-printed JSON.
This helper is intentionally design-point focused: it serializes only
parameters so command-line evaluators can consume the resulting file
as an input payload without needing optimizer metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output_path
|
Union[str, Path]
|
Target JSON path. |
required |
Returns:
| Type | Description |
|---|---|
Path
|
Resolved path of the written file. |
Source code in src/aid2e/optimizers/base.py
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | |
compute_pareto_front(trials, objective_names, objective_directions=None)
¶
Extract non-dominated (Pareto-optimal) trials from a collection of completed trials.
Objectives are compared using objective_directions. Minimization is the
default; maximization objectives treat larger values as better. For
single-objective problems the function returns the best trial under that
objective's direction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trials
|
List[Trial]
|
Iterable of Trial objects. Only trials whose |
required |
objective_names
|
List[str]
|
Ordered list of objective metric keys that must be
present in each trial's |
required |
objective_directions
|
Optional[Dict[str, Any]]
|
Optional mapping from objective name to
|
None
|
Returns:
| Type | Description |
|---|---|
List[Trial]
|
List of non-dominated Trial objects ordered by their original |
List[Trial]
|
position in |
List[Trial]
|
trials are available. |
Examples:
>>> from aid2e.optimizers.base import Trial, compute_pareto_front
>>> t1 = Trial(index=0, parameters={}, metrics={"f1": 1.0, "f2": 3.0}, status="completed")
>>> t2 = Trial(index=1, parameters={}, metrics={"f1": 2.0, "f2": 1.0}, status="completed")
>>> t3 = Trial(index=2, parameters={}, metrics={"f1": 0.5, "f2": 2.0}, status="completed")
>>> front = compute_pareto_front([t1, t2, t3], ["f1", "f2"])
>>> {t.index for t in front}
{0, 1, 2}
Notes
Uses NumPy for vectorised comparisons when available; falls back to a pure-Python O(n²) loop otherwise. For production workloads with thousands of trials, the NumPy path is strongly recommended.
Source code in src/aid2e/optimizers/base.py
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 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 | |