Plan: Multi-Objective Optimization Engine
Context
Section titled “Context”The current optimizer (optimizer.py) is a greedy constraint-fixer that tries one strategy per iteration. The Pareto code (pareto.py) does brute-force non-dominated sorting on a fixed hardware catalog with 3 hardcoded objectives. Design exploration — understanding the feasible region, tradeoff surfaces, and parameter sensitivity — is almost more valuable than any single optimal point. We need a proper MOO engine with concurrent evaluation, optional K8s offloading, and MCP server integration for the LLM agent.
Research basis: docs/multi-objective-optimization-research.md (34 references, DAC/NeurIPS/ICML papers on MOO for chip design).
Architecture: 3-Layer Pipeline
Section titled “Architecture: 3-Layer Pipeline”User requirements + constraints | v +---------------------------+ | Layer 1: MAP-Elites | Fast atlas on analytical models | (5K-10K evals, ~seconds) | "Here's what the design space looks like" +-------------+-------------+ | seed points + feasibility map v +---------------------------+ | Layer 2: Bayesian BO | Refined Pareto front + sensitivity | qNEHVI + exploration | "Here's the tradeoff surface" | (100-200 evals) | "Here's where we're uncertain" +-------------+-------------+ | Pareto front + GP posteriors v +---------------------------+ | Layer 3: LLM Interpret | ArchitectAgent explains tradeoffs, | (existing agent) | suggests design point based on priorities +---------------------------+
For >4 objectives: Layer 2 swaps from BO to NSGA-III/MOEA/D automatically.Deliverables
Section titled “Deliverables”1. NEW: src/embodied_ai_architect/graphs/moo/__init__.py
Section titled “1. NEW: src/embodied_ai_architect/graphs/moo/__init__.py”Package init exporting public API: DesignSpace, DesignEvaluator, OptimizationEngine, OptimizationResult.
2. NEW: src/embodied_ai_architect/graphs/moo/design_space.py
Section titled “2. NEW: src/embodied_ai_architect/graphs/moo/design_space.py”Formal design space definition with mixed discrete/continuous variables.
DesignVariable(BaseModel)— name, var_type (integer/continuous/categorical), bounds, choicesDesignSpace(BaseModel)— variables, objectives, directions, constraint boundssample_random(n)→ LHS initial sampleencode(params_dict)→ numpy array for optimizerdecode(x_array)→ params dict for evaluatorto_pymoo_problem_kwargs()→ pymoo problem definitionto_botorch_bounds()→ torch tensor bounds
create_soc_design_space(constraints)— factory with default SoC variables:- process_nm: categorical [2..180] (from
technology.pyTECHNOLOGY_NODES) - clock_mhz: continuous [100, 3000]
- array_rows/cols: integer [2, 64]
- sram_kb: integer [32, 2048]
- num_compute_tiles: integer [1, 16]
- noc_link_width_bits: categorical [64, 128, 256, 512]
- process_nm: categorical [2..180] (from
3. NEW: src/embodied_ai_architect/graphs/moo/evaluator.py
Section titled “3. NEW: src/embodied_ai_architect/graphs/moo/evaluator.py”Wraps existing specialists into a callable objective function. Thread-safe, pure function.
EvaluationResult(BaseModel)— design_params, objectives dict, constraints_satisfied, feasibleDesignEvaluatorclass:__init__(design_space, base_state, constraint_bounds)— captures the workload contextevaluate(params_dict) -> EvaluationResult— called 100-10K timesevaluate_batch(param_list) -> list[EvaluationResult]
Reuses (not duplicates):
SoCComposition+IPBlockConfigfromgraphs/ip_blocks.py— builds design from paramsestimate_manufacturing_cost()fromgraphs/manufacturing.py— cost objectiveget_technology()fromgraphs/technology.py— process-aware PPA- PPA estimation logic from
specialists.py_estimate_power,_estimate_latency,_estimate_area
4. NEW: src/embodied_ai_architect/graphs/moo/executor.py
Section titled “4. NEW: src/embodied_ai_architect/graphs/moo/executor.py”Concurrent evaluation backends with a shared EvalBackend protocol.
EvalBackend(Protocol)—submit_batch(params) -> list[EvaluationResult],shutdown()LocalThreadExecutor—ThreadPoolExecutor(max_workers=8)for analytical modelsKubernetesEvalExecutor— extends existing K8s pattern for batch evaluation jobs
5. NEW: src/embodied_ai_architect/graphs/moo/map_elites.py
Section titled “5. NEW: src/embodied_ai_architect/graphs/moo/map_elites.py”Layer 1: Fast design space illumination.
MAPElitesConfig(BaseModel)— feature_dimensions, resolution, n_iterations, batch_sizeMAPElitesResult(BaseModel)— grid (cell → best design), coverage, best_per_objectiveMAPElitesclass:run(callback)→ fills the grid atlas_mutate(),_crossover(),_feature_to_cell()- Uses
executor.submit_batch()for parallel evaluation (batch_size=64 per iteration)
Custom implementation (~200 lines). pymoo lacks MAP-Elites; the algorithm is simple enough.
6. NEW: src/embodied_ai_architect/graphs/moo/bayesian_opt.py
Section titled “6. NEW: src/embodied_ai_architect/graphs/moo/bayesian_opt.py”Layer 2: Sample-efficient Pareto refinement. Requires BoTorch (optional dep).
BayesianOptConfig(BaseModel)— n_initial, n_iterations, batch_size, exploration_scheduleSensitivityResult(BaseModel)— parameter_name, sobol_total, sobol_first_order, lengthscaleBayesianOptResult(BaseModel)— pareto_front, hypervolume, sensitivity, convergence_historyBayesianMOOclass:run(callback)→ qNEHVI loop with exploration-exploitation scheduleget_sensitivity()→ extracts from GP lengthscales (free after fitting)predict(params)→ mean + std per objectiveexplain_tradeoff(point_a, point_b)→ parameter deltas + GP gradient analysis- Warm-starts from MAP-Elites results (Layer 1 → Layer 2 handoff)
Exploration-exploitation schedule:
alpha = max(0.0, 1.0 - 2.0 * (iteration / budget))acquisition = alpha * GP_variance + (1 - alpha) * EHVI7. NEW: src/embodied_ai_architect/graphs/moo/nsga3.py
Section titled “7. NEW: src/embodied_ai_architect/graphs/moo/nsga3.py”Layer 3: Many-objective fallback (>4 objectives). Requires pymoo.
NSGA3Config(BaseModel)— pop_size, n_generations, reference_directionsNSGA3Result(BaseModel)— pareto_front, hypervolume, generation_historyNSGA3MOOclass wrapping pymoo’sNSGA3with ourDesignSpaceand evaluator
8. NEW: src/embodied_ai_architect/graphs/moo/engine.py
Section titled “8. NEW: src/embodied_ai_architect/graphs/moo/engine.py”Orchestrates the 3-layer pipeline.
OptimizationConfig(BaseModel)— layers (auto/map_elites/bayesian/nsga3), per-layer configs, backend, max_workersOptimizationResult(BaseModel)— pareto_front, hypervolume, knee_point, sensitivity, atlas, convergence_historyOptimizationEngineclass:- Auto-selects layers: <=4 objectives → MAP-Elites + BO; >4 → MAP-Elites + NSGA-III
run(callback)→ executes pipeline, Layer 1 seeds Layer 2get_pareto_front(),get_sensitivity(),explain_tradeoff()— queryable during/after run
9. NEW: src/embodied_ai_architect/graphs/moo/specialist.py
Section titled “9. NEW: src/embodied_ai_architect/graphs/moo/specialist.py”Bridge to existing dispatcher pattern: moo_explorer(task, state) -> dict.
- Same signature as all specialists:
(TaskNode, SoCDesignState) -> dict - Reads: constraints, workload_profile
- Writes:
pareto_results(backward compatible),moo_results(new field) - Supports
task.metadata["fast_mode"]for reduced evaluation budgets
10. NEW: src/embodied_ai_architect/graphs/moo/k8s_evaluator.py
Section titled “10. NEW: src/embodied_ai_architect/graphs/moo/k8s_evaluator.py”K8s evaluation backend for expensive evaluations (synthesis, simulation).
- Extends existing K8s Job pattern from
agents/benchmark/backends/kubernetes.py - Concurrent job submission (not sequential like existing
execute_parallel) - Semaphore-based concurrency control (
max_parallel_jobs) - EDA license management via K8s secrets (
eda_license_secretmount) - Result collection as jobs complete (not in submission order)
11. NEW: src/embodied_ai_architect/mcp/__init__.py + server.py + session.py
Section titled “11. NEW: src/embodied_ai_architect/mcp/__init__.py + server.py + session.py”MCP server exposing optimization as tools for the LLM agent. NOT in the hot evaluation loop — MCP is the interface layer, not the compute layer.
Tools (Dual-Response pattern):
start_exploration(goal, constraints, config)→ session_id (async, optimization runs in background thread)get_pareto_front(session_id, top_n=5)→ preview (top-5 for LLM) + ResourceLink (full front)get_sensitivity(session_id)→ Sobol indices + GP lengthscalesexplain_tradeoff(session_id, point_a, point_b)→ parameter/objective deltasget_exploration_status(session_id)→ layer, iteration, progress
Resources:
hardware_catalog→ Dual-Response: 5-entry preview + paginated ResourceLinkprocess_nodes→ 17-node technology database
Session management (session.py):
OptimizationSession— runs engine in background thread, queryable statusSessionManager— tracks active sessions, cleanup expired
12. NEW: src/embodied_ai_architect/llm/optimization_tools.py
Section titled “12. NEW: src/embodied_ai_architect/llm/optimization_tools.py”LLM tool definitions following the get_*_tool_definitions() + create_*_tool_executors() pattern from llm/codebase_tools.py.
5 tools: explore_design_space, get_pareto_front, get_design_sensitivity, explain_design_tradeoff, suggest_optimal_design.
When MCP server available: tools proxy to MCP (async, stateful sessions). When MCP not available: tools run optimization inline (blocking).
13. MODIFY: src/embodied_ai_architect/llm/tools.py
Section titled “13. MODIFY: src/embodied_ai_architect/llm/tools.py”Register optimization tools with try/except guard (HAS_MOO flag).
14. NEW: src/embodied_ai_architect/cli/commands/optimize.py
Section titled “14. NEW: src/embodied_ai_architect/cli/commands/optimize.py”Click command group:
branes optimize explore --goal "..." --power 5 --latency 33 [--fast] [--backend kubernetes]branes optimize show-front [session-id] [--top 10]branes optimize sensitivity [session-id]branes optimize explain [session-id] --points 0,315. MODIFY: src/embodied_ai_architect/cli/__init__.py
Section titled “15. MODIFY: src/embodied_ai_architect/cli/__init__.py”Register optimize command group.
16. MODIFY: src/embodied_ai_architect/graphs/soc_state.py
Section titled “16. MODIFY: src/embodied_ai_architect/graphs/soc_state.py”Add moo_results: dict field to SoCDesignState and create_initial_soc_state().
17. MODIFY: src/embodied_ai_architect/graphs/specialists.py
Section titled “17. MODIFY: src/embodied_ai_architect/graphs/specialists.py”Register moo_explorer in create_default_dispatcher() with try/except guard.
18. MODIFY: pyproject.toml
Section titled “18. MODIFY: pyproject.toml”New optional dependency groups:
optimization = ["pymoo>=0.6.0", "botorch>=0.11.0", "gpytorch>=1.12", "scipy>=1.10.0"]mcp = ["mcp>=1.0.0", "uvicorn>=0.25.0", "httpx>=0.25.0"]19. Tests
Section titled “19. Tests”| File | Tests | Coverage |
|---|---|---|
tests/test_design_space.py | ~10 | Variable types, encode/decode roundtrip, factory, pymoo/botorch export |
tests/test_moo_evaluator.py | ~8 | Single eval, batch, feasibility, thread safety (100 concurrent), reuse of PPA logic |
tests/test_map_elites.py | ~6 | Init, small run, mutation bounds, feature→cell, result structure, coverage |
tests/test_bayesian_moo.py | ~8 | Init, warm-start, small run, sensitivity, predict, explain (skip if no botorch) |
tests/test_moo_engine.py | ~8 | Auto layer selection, full pipeline, result compatibility, specialist integration |
tests/test_mcp_server.py | ~6 | Tool calls, dual-response, session lifecycle (skip if no mcp) |
File Summary
Section titled “File Summary”| File | Action | Depends On |
|---|---|---|
graphs/moo/__init__.py | CREATE | — |
graphs/moo/design_space.py | CREATE | technology.py, soc_state.py |
graphs/moo/evaluator.py | CREATE | ip_blocks.py, manufacturing.py, specialists.py |
graphs/moo/executor.py | CREATE | evaluator.py |
graphs/moo/map_elites.py | CREATE | design_space.py, executor.py (numpy only) |
graphs/moo/bayesian_opt.py | CREATE | design_space.py, executor.py (needs botorch) |
graphs/moo/nsga3.py | CREATE | design_space.py, executor.py (needs pymoo) |
graphs/moo/engine.py | CREATE | map_elites, bayesian_opt, nsga3 |
graphs/moo/specialist.py | CREATE | engine.py |
graphs/moo/k8s_evaluator.py | CREATE | executor.py, kubernetes backend pattern |
mcp/__init__.py | CREATE | — |
mcp/server.py | CREATE | engine.py, session.py |
mcp/session.py | CREATE | engine.py |
llm/optimization_tools.py | CREATE | engine.py |
cli/commands/optimize.py | CREATE | engine.py |
llm/tools.py | MODIFY | optimization_tools.py |
cli/__init__.py | MODIFY | optimize.py |
graphs/soc_state.py | MODIFY | — |
graphs/specialists.py | MODIFY | moo/specialist.py |
pyproject.toml | MODIFY | — |
| 6 test files | CREATE | — |
Key Design Decisions
Section titled “Key Design Decisions”-
Evaluation is a pure function —
DesignEvaluator.evaluate()has no side effects, safe forThreadPoolExecutor. Reuses existingSoCComposition+estimate_manufacturing_cost, no duplication. -
MCP is the interface layer, NOT the compute layer — 5K-10K evaluations/sec need microsecond overhead. MCP handles LLM↔engine interaction (start exploration, query front, explain tradeoff). The hot loop is
ThreadPoolExecutoror K8s Jobs. -
Layer handoff — MAP-Elites results seed BO initial observations. Avoids redundant random sampling. BO warm-starts from the atlas’s best points.
-
K8s for expensive evaluations — Analytical model evals stay local (ThreadPool). Synthesis/simulation jobs go to K8s with concurrency control, license management via secrets.
-
Auto layer selection — <=4 objectives: MAP-Elites → Bayesian BO. >4 objectives: MAP-Elites → NSGA-III. User can override.
-
Backward compatible — Results flow into existing
pareto_resultsformat. Newmoo_resultsfield for rich data. Existingdesign_explorerconsumers see no change.
Implementation Sequence
Section titled “Implementation Sequence”Build in this order (each step testable independently):
design_space.py+ tests — Pure data model, no external depsevaluator.py+ tests — Wraps existing specialists, validate thread safetyexecutor.py— LocalThreadExecutor firstmap_elites.py+ tests — Layer 1, needs only numpyengine.py+ tests — Orchestration with MAP-Elites only initiallyspecialist.py— Register with dispatcher, integration testcli/commands/optimize.py— CLI commandsbayesian_opt.py+ tests — Layer 2, requires botorchnsga3.py— Layer 3, requires pymoomcp/+ tests — MCP server integrationllm/optimization_tools.py— LLM tool wrappersk8s_evaluator.py— K8s evaluation backendpyproject.toml— Optional dependency groups
Verification
Section titled “Verification”# Install with optimization supportpip install -e ".[optimization]"
# Run core tests (no optional deps needed for MAP-Elites)pytest tests/test_design_space.py tests/test_moo_evaluator.py tests/test_map_elites.py tests/test_moo_engine.py -v
# Run BO tests (requires botorch)pytest tests/test_bayesian_moo.py -v
# Run MCP tests (requires mcp)pip install -e ".[mcp]"pytest tests/test_mcp_server.py -v
# CLI testbranes optimize explore --goal "drone perception SoC" --power 5 --latency 33 --fast
# Chat test (requires ANTHROPIC_API_KEY)branes chat> explore the design space for a drone SoC with 5W power budget and 33ms latency
# Existing tests still passpytest tests/ -v
# Lintruff check src/embodied_ai_architect/graphs/moo/ src/embodied_ai_architect/mcp/black src/embodied_ai_architect/graphs/moo/ src/embodied_ai_architect/mcp/ --check --line-length 100