# Optimization Workflow Optimization sits at the end of the Monata workflow. It should reuse the same circuit authoring, simulation, and measurement functions you already use for manual design checks. ```text design variables -> simulation task -> metric/spec evaluation -> optimizer ``` ## When to Optimize Use optimization after you can already run a deterministic simulation and extract stable metrics. If a single simulation is not understood, an optimizer will only make failures harder to diagnose. ## Design Variables Design variables describe tunable parameters such as transistor width, load capacitance, bias current, or compensation capacitance. ```python from monata.optim import DesignVariable variables = [ DesignVariable("w_p", min=0.5e-6, max=8e-6), DesignVariable("w_n", min=0.5e-6, max=4e-6), ] ``` ## Objectives and Constraints Objectives and constraints should be built from the same metric functions used in measurement specs. ```python from monata.optim import Objective, Constraint objectives = [ Objective("delay", direction="minimize"), ] constraints = [ Constraint("voh", min=1.1), ] ``` ## Choosing an Optimizer | Optimizer | Best for | | --- | --- | | Bayesian optimization | Expensive simulations with a small number of variables | | NSGA-II | Multi-objective tradeoffs and broader design-space exploration | ## Circuit Optimization Loop The optimizer should not know about backend details. It should receive a callable that applies parameter values, runs a simulation, and returns metrics. ```python def evaluate(params): task = SimTask( circuit=circuit, analysis_spec=tran, param_overrides=params, simulator="ngspice-subprocess", ) result = executor.submit(task).result() if result.status != "ok": raise RuntimeError(result.error_message) return { "delay": propagation_delay(result), "voh": max(result.waveforms["out"]), } ``` Keep this loop deterministic before enabling parallel execution or larger search spaces.