Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-12 08:24:56

0001 """Pydantic configuration model for PyMOO-based optimizers.
0002 
0003 Supported algorithms and their best use cases:
0004 
0005 - ``ga``: Single-objective Genetic Algorithm.
0006 - ``nsga2``: NSGA-II — fast, well-tested, good for 2-3 objectives.
0007 - ``nsga3``: NSGA-III — structured reference directions, 3+ objectives.
0008 - ``moead``: MOEA/D — weight-decomposition, highly customisable, 3+ objectives.
0009 
0010 Auto-registration with the canonical optimizer config registry happens at
0011 import time so configuration utilities can resolve ``"pymoo"`` lazily.
0012 
0013 Project: AID2E v0.0.0 — AI assisted Detector Design for EIC
0014 Homepage: https://aid2e.github.io/AID2E-framework
0015 Repository: https://github.com/aid2e/AID2E-framework.git
0016 """
0017 
0018 from typing import Literal, Optional
0019 from pydantic import BaseModel, Field
0020 
0021 from aid2e.utilities.configurations.optimization_registry import register
0022 
0023 
0024 PyMOOAlgorithm = Literal["ga", "nsga2", "nsga3", "moead"]
0025 
0026 
0027 class PyMOOOptimizerConfig(BaseModel):
0028     """Configuration for PyMOO-based evolutionary optimizers.
0029 
0030     Attributes:
0031         algorithm: Optional evolutionary algorithm identifier. If omitted,
0032             AID2E infers ``"ga"`` for single-objective problems and
0033             ``"nsga2"`` for multi-objective problems.
0034         pop_size: Population size (number of individuals per generation).
0035         n_offsprings: Number of offspring generated each generation.  ``None``
0036             defaults to ``pop_size``.
0037         crossover_prob: Simulated Binary Crossover (SBX) probability.
0038         crossover_eta: SBX distribution index — larger values produce offspring
0039             closer to the parents.
0040         mutation_eta: Polynomial mutation distribution index.
0041         n_iterations: Number of generations to run when using this config in
0042             declarative/runtime-driven flows.
0043         n_partitions: Reference-direction partitions for NSGA-III and MOEA/D.
0044             The total number of reference directions grows combinatorially with
0045             this value and ``n_objectives``.  Ignored for NSGA-II.
0046         seed: Random seed for reproducibility.  ``None`` yields non-deterministic
0047             results.
0048         verbose: Whether PyMOO prints per-generation progress to stdout.
0049 
0050     Examples:
0051         >>> config = PyMOOOptimizerConfig(
0052         ...     pop_size=100,
0053         ...     seed=42,
0054         ... )
0055         >>> config.algorithm is None
0056         True
0057         >>> config2 = PyMOOOptimizerConfig(algorithm="nsga3", n_partitions=12)
0058 
0059     Notes:
0060         - ``ga`` is the recommended default for single-objective problems.
0061         - NSGA-II is the recommended default for 2-objective problems.
0062         - For 3+ objectives consider NSGA-III or MOEA/D — their reference
0063           direction structures are better suited to high-dimensional fronts.
0064         - ``n_partitions`` has a strong effect on runtime for NSGA-III/MOEA/D;
0065           start with 12 for 2-3 objectives and reduce for 4+ objectives.
0066     """
0067 
0068     algorithm: Optional[PyMOOAlgorithm] = Field(
0069         default=None,
0070         description=(
0071             "Optional evolutionary algorithm. If omitted, AID2E infers 'ga' "
0072             "for single-objective problems and 'nsga2' for multi-objective problems."
0073         ),
0074     )
0075     pop_size: int = Field(
0076         default=100,
0077         ge=2,
0078         description="Population size — number of candidate solutions per generation.",
0079     )
0080     n_offsprings: Optional[int] = Field(
0081         default=None,
0082         ge=1,
0083         description=(
0084             "Number of offspring per generation. "
0085             "Defaults to pop_size when None."
0086         ),
0087     )
0088     crossover_prob: float = Field(
0089         default=0.9,
0090         ge=0.0,
0091         le=1.0,
0092         description="SBX crossover probability.",
0093     )
0094     crossover_eta: float = Field(
0095         default=15.0,
0096         gt=0.0,
0097         description="SBX crossover distribution index.",
0098     )
0099     mutation_eta: float = Field(
0100         default=20.0,
0101         gt=0.0,
0102         description="Polynomial mutation distribution index.",
0103     )
0104     n_iterations: int = Field(
0105         default=50,
0106         ge=1,
0107         description="Number of generations for runtime-driven optimization loops.",
0108     )
0109     n_partitions: int = Field(
0110         default=12,
0111         ge=1,
0112         description=(
0113             "Reference-direction partitions for NSGA-III and MOEA/D. "
0114             "Ignored for NSGA-II."
0115         ),
0116     )
0117     seed: Optional[int] = Field(
0118         default=None,
0119         description="Random seed. None means non-deterministic.",
0120     )
0121     verbose: bool = Field(
0122         default=False,
0123         description="Print per-generation statistics to stdout.",
0124     )
0125 
0126     def resolve_algorithm(self, n_objectives: int) -> PyMOOAlgorithm:
0127         """Resolve the algorithm for the given objective count.
0128 
0129         Args:
0130             n_objectives: Number of objectives in the optimization problem.
0131 
0132         Returns:
0133             Concrete PyMOO algorithm identifier.
0134 
0135         Raises:
0136             ValueError: If the configured explicit algorithm is incompatible
0137                 with the objective count.
0138         """
0139         if n_objectives < 1:
0140             raise ValueError("n_objectives must be >= 1")
0141 
0142         if self.algorithm is None:
0143             return "ga" if n_objectives == 1 else "nsga2"
0144 
0145         if self.algorithm == "ga" and n_objectives != 1:
0146             raise ValueError(
0147                 "PyMOO algorithm 'ga' only supports single-objective problems. "
0148                 f"Received {n_objectives} objectives."
0149             )
0150 
0151         if self.algorithm in {"nsga2", "nsga3", "moead"} and n_objectives == 1:
0152             raise ValueError(
0153                 f"PyMOO algorithm '{self.algorithm}' requires a multi-objective "
0154                 "problem. Use 'ga' or omit 'algorithm' for single-objective optimization."
0155             )
0156 
0157         return self.algorithm
0158 
0159 
0160 # Auto-register with the optimizer config registry
0161 register("pymoo", PyMOOOptimizerConfig)