Skip to content

catalog

catalog

Generic optimizer catalog and strict construction.

The catalog is dependency-light: optional optimizer implementations are imported only when their entry is explicitly resolved.

OptimizerSpec dataclass

OptimizerSpec(key: str, label: str, method: str, evaluator: str, gradient_mode: str = 'none', fd_step: float = 0.0001, extra: Mapping[str, Any] = dict())

One immutable registered optimizer configuration.

regularization property

regularization: float

L2 regularization requested by this catalog entry.

optimizer_spec

optimizer_spec(value: str | OptimizerSpec) -> OptimizerSpec

Resolve a catalog key or return a validated spec.

Source code in q2mm/optimizers/catalog.py
def optimizer_spec(value: str | OptimizerSpec) -> OptimizerSpec:
    """Resolve a catalog key or return a validated spec."""
    if isinstance(value, OptimizerSpec):
        return value
    try:
        return OPTIMIZER_CATALOG[value]
    except KeyError:
        raise ValueError(f"Unknown optimizer {value!r}; choose one of {sorted(OPTIMIZER_CATALOG)}.") from None

optimizer_option_names

optimizer_option_names(value: str | OptimizerSpec) -> frozenset[str]

Return the accepted option keys for a catalog entry.

Source code in q2mm/optimizers/catalog.py
def optimizer_option_names(value: str | OptimizerSpec) -> frozenset[str]:
    """Return the accepted option keys for a catalog entry."""
    return _allowed_options(optimizer_spec(value).method)

resolve_optimizer

resolve_optimizer(value: str | OptimizerSpec, options: Mapping[str, Any] | None = None) -> tuple[Any, dict[str, Any]]

Construct an optimizer and return its exact effective settings.

Source code in q2mm/optimizers/catalog.py
def resolve_optimizer(
    value: str | OptimizerSpec,
    options: Mapping[str, Any] | None = None,
) -> tuple[Any, dict[str, Any]]:
    """Construct an optimizer and return its exact effective settings."""
    spec = optimizer_spec(value)
    supplied = dict(options or {})
    unknown = set(supplied) - _allowed_options(spec.method)
    if unknown:
        raise ValueError(f"Unknown options for optimizer {spec.key!r}: {sorted(unknown)}.")
    cfg = {**_COMMON_DEFAULTS, **supplied}
    method = spec.method
    extra = spec.extra
    maxiter = cfg["maxiter"]

    if method in ("L-BFGS-B", "Nelder-Mead", "Powell"):
        from q2mm.optimizers.scipy_opt import ScipyOptimizer

        effective = 500 if maxiter is None else int(maxiter)
        opt: Any = ScipyOptimizer(
            method=method,
            maxiter=effective,
            ftol=float(cfg["ftol"]),
            verbose=False,
            fc_fraction=cfg["fc_fraction"],
            eq_fraction=cfg["eq_fraction"],
        )
        return opt, {
            "kind": "scipy",
            "method": method,
            "maxiter": effective,
            "ftol": float(cfg["ftol"]),
            "gtol": opt.gtol,
            "maxls": opt.maxls,
            "eps": opt.eps,
            "fc_fraction": cfg["fc_fraction"],
            "eq_fraction": cfg["eq_fraction"],
            "use_bounds": opt.use_bounds,
            "analytical_parameter_scaling": "bound-normalized",
        }
    if method == "cycling":
        effective_cfg: dict[str, Any] = {
            "max_params": int(cfg["max_params"]),
            "convergence": float(cfg["convergence"]),
            "max_cycles": int(cfg["max_cycles"]),
        }
        if maxiter is not None:
            effective_cfg["full_maxiter"] = int(maxiter)
            effective_cfg["simp_maxiter"] = int(maxiter)
        if "full_method" in extra:
            effective_cfg["full_method"] = extra["full_method"]
        return _CyclingOptimizer(**effective_cfg), {"kind": "cycling", **effective_cfg}
    if method.startswith("optax:"):
        from q2mm.optimizers.optax import OptaxOptimizer

        steps = 2000 if maxiter is None else int(maxiter)
        kwargs: dict[str, Any] = {
            "optimizer": method.split(":", 1)[1],
            "max_steps": steps,
            "learning_rate": float(cfg["learning_rate"]),
            "verbose": False,
        }
        if "schedule" in extra:
            kwargs["schedule"] = extra["schedule"]
        return OptaxOptimizer(**kwargs), {
            "kind": "optax",
            "optimizer": kwargs["optimizer"],
            "max_steps": steps,
            "schedule": extra.get("schedule"),
            "learning_rate": float(cfg["learning_rate"]),
        }
    if method.startswith("jaxopt:"):
        from q2mm.optimizers.jaxopt_opt import JaxOptOptimizer

        effective = 200 if maxiter is None else int(maxiter)
        name = method.split(":", 1)[1]
        return JaxOptOptimizer(method=name, maxiter=effective, verbose=False), {
            "kind": "jaxopt",
            "method": name,
            "maxiter": effective,
        }
    if method.startswith("basinhopping"):
        from q2mm.optimizers.basinhopping import BasinHoppingOptimizer

        local_maxiter = 200 if maxiter is None else int(maxiter)
        kwargs = {"verbose": False, "local_maxiter": local_maxiter, "seed": int(cfg["seed"])}
        if "niter" in extra:
            kwargs["niter"] = int(extra["niter"])
        if "T" in extra:
            kwargs["T"] = float(extra["T"])
        return BasinHoppingOptimizer(**kwargs), {
            "kind": "basinhopping",
            "local_maxiter": local_maxiter,
            "niter": extra.get("niter"),
            "T": extra.get("T"),
            "seed": int(cfg["seed"]),
        }
    if method.startswith("multi:"):
        from q2mm.optimizers.multistart import MultiStartOptimizer
        from q2mm.optimizers.scipy_opt import ScipyOptimizer

        inner_maxiter = 500 if maxiter is None else int(maxiter)
        inner_name = method.split(":", 1)[1]
        inner = ScipyOptimizer(method=inner_name, maxiter=inner_maxiter, verbose=False)
        kwargs = {"optimizer": inner, "verbose": False, "seed": int(cfg["seed"])}
        if "n_starts" in extra:
            kwargs["n_starts"] = int(extra["n_starts"])
        return MultiStartOptimizer(**kwargs), {
            "kind": "multistart",
            "inner_method": inner_name,
            "inner_maxiter": inner_maxiter,
            "n_starts": extra.get("n_starts"),
            "seed": int(cfg["seed"]),
        }
    raise ValueError(f"Unknown optimizer method {method!r}.")

expected_result_gradient

expected_result_gradient(spec: OptimizerSpec) -> str

Return the gradient provenance an optimizer result must report.

Source code in q2mm/optimizers/catalog.py
def expected_result_gradient(spec: OptimizerSpec) -> str:
    """Return the gradient provenance an optimizer result must report."""
    if spec.evaluator == "jax":
        return "analytical"
    if spec.gradient_mode == "finite_difference":
        return "finite_difference"
    if spec.method in ("Nelder-Mead", "Powell"):
        return "none"
    return "finite_difference"