Download src/sr_harness/utils/constant_optimizer.py from YuMeow/SRHarness: direct link, hf CLI and curl.
- Browser
- Download file 9.49 kB
-
https://huggingface.co/spaces/YuMeow/SRHarness/resolve/main/src/sr_harness/utils/constant_optimizer.py
- Command line
-
hf download hf://spaces/YuMeow/SRHarness/src/sr_harness/utils/constant_optimizer.py
-
curl -L -o constant_optimizer.py https://huggingface.co/spaces/YuMeow/SRHarness/resolve/main/src/sr_harness/utils/constant_optimizer.py
9.49 kB
| # Copyright (c) 2026-present, Yumeow. Licensed under the MIT License. | |
| """Numerical optimization for parameters and opted-in numeric literals.""" | |
| from __future__ import annotations | |
| from dataclasses import dataclass, replace as dataclass_replace | |
| from typing import Any, Dict | |
| import warnings | |
| import numpy as np | |
| import sr_harness_engine as engine | |
| from scipy.optimize import differential_evolution, least_squares | |
| from sr_harness_engine.evaluation import grouped_parameter_key | |
| from sr_harness_engine.tree import children, with_children, transform | |
| class ConstantOptimizerConfig: | |
| """Numerical budget and reproducibility controls for ``fit_constants``.""" | |
| random_state: int = 0 | |
| n_restarts: int = 3 | |
| max_nfev: int = 700 | |
| differential_evolution_maxiter: int = 15 | |
| differential_evolution_popsize: int = 5 | |
| use_global_search: bool = True | |
| snap_exponents: bool = True | |
| use_eps: float = 1e-8 | |
| class _ParameterSpec: | |
| name: str | |
| label: Any | None | |
| initial: float | |
| lower: float | |
| upper: float | |
| literal: bool = False | |
| def _parameterize_literals( | |
| expression: engine.Expression, | |
| data: Dict[str, np.ndarray], | |
| ) -> tuple[engine.Expression, list[_ParameterSpec]]: | |
| specs: list[_ParameterSpec] = [] | |
| named: dict[str, int] = {} | |
| grouped: dict[str, engine.GroupedParameter] = {} | |
| literal_index = 0 | |
| def visit( | |
| node: engine.Expression, | |
| parent: engine.Expression | None = None, | |
| child_index: int | None = None, | |
| ) -> engine.Expression: | |
| nonlocal literal_index | |
| if isinstance(node, engine.Number): | |
| name = f"__literal_{literal_index}" | |
| literal_index += 1 | |
| value = float(node.value) | |
| limit = max(100.0, 10.0 * abs(value) + 1.0) | |
| lower, upper = -limit, limit | |
| if isinstance(parent, engine.Binary) and parent.operator == "**" and child_index == 1: | |
| lower, upper = -10.0, 10.0 | |
| if ( | |
| isinstance(parent, engine.Binary) | |
| and parent.operator == "-" | |
| and child_index == 1 | |
| and isinstance(parent.left, engine.Symbol) | |
| and parent.left.name in data | |
| ): | |
| feature = np.asarray(data[parent.left.name], dtype=float).reshape(-1) | |
| feature = feature[np.isfinite(feature)] | |
| if feature.size: | |
| width = float(np.max(feature) - np.min(feature)) | |
| margin = max(0.2 * width, 10.0) | |
| lower = float(np.min(feature) - margin) | |
| upper = float(np.max(feature) + margin) | |
| specs.append(_ParameterSpec(name, None, value, lower, upper, literal=True)) | |
| return engine.Parameter(name, value) | |
| if isinstance(node, engine.Parameter): | |
| if node.name not in named: | |
| initial = 1.0 if node.value is None else float(node.value) | |
| limit = max(100.0, 10.0 * abs(initial) + 1.0) | |
| named[node.name] = len(specs) | |
| specs.append(_ParameterSpec(node.name, None, initial, -limit, limit)) | |
| return node | |
| if isinstance(node, engine.GroupedParameter): | |
| key = grouped_parameter_key(node) | |
| grouped.setdefault(key, node) | |
| return dataclass_replace(node, by=visit(node.by, node, 0)) | |
| transformed_children = tuple( | |
| visit(child, node, index) for index, child in enumerate(children(node)) | |
| ) | |
| return with_children(node, transformed_children) | |
| parameterized = visit(expression) | |
| for key, node in grouped.items(): | |
| labels = np.asarray(node.by.evaluate(data), dtype=object).reshape(-1) | |
| unique = [] | |
| for label in labels: | |
| label = label.item() if isinstance(label, np.generic) else label | |
| if label not in unique: | |
| unique.append(label) | |
| supplied = dict(node.value or {}) | |
| for label in unique: | |
| initial = float(supplied.get(label, node.default if node.default is not None else 1.0)) | |
| limit = max(100.0, 10.0 * abs(initial) + 1.0) | |
| specs.append(_ParameterSpec(key, label, initial, -limit, limit)) | |
| return parameterized, specs | |
| def _unpack(raw: np.ndarray, specs: list[_ParameterSpec]) -> dict[str, Any]: | |
| result: dict[str, Any] = {} | |
| for value, spec in zip(raw, specs): | |
| if spec.label is None: | |
| result[spec.name] = float(value) | |
| else: | |
| result.setdefault(spec.name, {})[spec.label] = float(value) | |
| return result | |
| def _bind( | |
| expression: engine.Expression, | |
| parameters: dict[str, Any], | |
| literal_names: set[str], | |
| ) -> engine.Expression: | |
| def bind(node: engine.Expression) -> engine.Expression: | |
| if isinstance(node, engine.Parameter) and node.name in parameters: | |
| value = float(parameters[node.name]) | |
| if node.name in literal_names: | |
| return engine.Number(value) | |
| return engine.Parameter(node.name, value) | |
| if isinstance(node, engine.GroupedParameter): | |
| key = grouped_parameter_key(node) | |
| if key in parameters: | |
| return dataclass_replace(node, value=dict(parameters[key])) | |
| return node | |
| return transform(expression, bind) | |
| def fit_constants( | |
| f: engine.Expression, | |
| data: Dict[str, np.ndarray], | |
| y: np.ndarray, | |
| *, | |
| config: ConstantOptimizerConfig | None = None, | |
| num_nodes: int | None = None, | |
| ) -> engine.Expression: | |
| """Return a fitted expression without modifying ``f``. | |
| This function is an explicit opt-in optimization operation, so numeric | |
| literals are temporarily promoted to independent parameters. Outside this | |
| function, literals remain fixed and only ``param(...)`` nodes are fitable. | |
| """ | |
| if not isinstance(f, engine.Expression): | |
| raise TypeError("f must be an sr_harness_engine.Expression") | |
| config = config or ConstantOptimizerConfig() | |
| target = np.asarray(y, dtype=float).reshape(-1) | |
| if target.size == 0 or not np.all(np.isfinite(target)): | |
| raise ValueError("y must contain at least one finite-only sample") | |
| arrays = {name: np.asarray(value) for name, value in data.items()} | |
| if num_nodes is None and any( | |
| np.asarray(value).reshape(-1).size != target.size | |
| for value in arrays.values() | |
| ): | |
| raise ValueError("all data arrays must have the same number of samples as y") | |
| expression, specs = _parameterize_literals(f.copy(), arrays) | |
| if not specs: | |
| return expression.copy() | |
| initial = np.asarray([spec.initial for spec in specs], dtype=float) | |
| lower = np.asarray([spec.lower for spec in specs], dtype=float) | |
| upper = np.asarray([spec.upper for spec in specs], dtype=float) | |
| scale = max(float(np.std(target)), float(np.max(np.abs(target))) * 1e-12, 1e-12) | |
| invalid = np.full(target.size, 1e6, dtype=float) | |
| def prediction(raw: np.ndarray) -> np.ndarray | None: | |
| try: | |
| with np.errstate(all="ignore"): | |
| value = np.asarray( | |
| expression.evaluate( | |
| arrays, | |
| parameters=_unpack(raw, specs), | |
| num_nodes=num_nodes, | |
| ), | |
| dtype=float, | |
| ).reshape(-1) | |
| if value.size == 1 and target.size != 1: | |
| value = np.full(target.size, float(value[0])) | |
| if value.size != target.size or not np.all(np.isfinite(value)): | |
| return None | |
| return value | |
| except (ArithmeticError, FloatingPointError, KeyError, TypeError, ValueError): | |
| return None | |
| def residual(raw: np.ndarray) -> np.ndarray: | |
| value = prediction(raw) | |
| return invalid if value is None else (value - target) / scale | |
| def loss(raw: np.ndarray) -> float: | |
| value = prediction(raw) | |
| return 1e100 if value is None else float(np.mean(np.square(value - target))) | |
| starts = [np.clip(initial, lower, upper)] | |
| rng = np.random.default_rng(config.random_state) | |
| for _ in range(max(0, config.n_restarts - 1)): | |
| starts.append(rng.uniform(lower, upper)) | |
| if config.use_global_search and len(specs) <= 12: | |
| with warnings.catch_warnings(): | |
| warnings.simplefilter("ignore") | |
| global_result = differential_evolution( | |
| loss, | |
| list(zip(lower, upper)), | |
| seed=config.random_state, | |
| maxiter=config.differential_evolution_maxiter, | |
| popsize=config.differential_evolution_popsize, | |
| polish=False, | |
| updating="immediate", | |
| ) | |
| starts.append(global_result.x) | |
| best = starts[0] | |
| best_loss = loss(best) | |
| for start in starts: | |
| with warnings.catch_warnings(): | |
| warnings.simplefilter("ignore") | |
| result = least_squares( | |
| residual, | |
| start, | |
| bounds=(lower, upper), | |
| max_nfev=config.max_nfev, | |
| xtol=1e-13, | |
| ftol=1e-13, | |
| gtol=1e-13, | |
| ) | |
| current_loss = loss(result.x) | |
| if current_loss < best_loss: | |
| best, best_loss = result.x, current_loss | |
| parameters = _unpack(best, specs) | |
| literal_names = {spec.name for spec in specs if spec.literal} | |
| return _bind(expression, parameters, literal_names) | |