Skip to main content

Cold-start MACE Bayesian optimization for mixed-variable EDA design spaces.

Project description

MACE EDA BO

Cold-start Bayesian optimization for mixed-variable EDA design spaces.

This first version keeps the HEBO-style MACE acquisition idea (LCB, EI, and PI) but changes the surrounding loop for discrete EDA-style spaces:

  • mixed variables: continuous, integer, categorical, boolean
  • optional legalize(config) hook for repairing invalid designs
  • optional canonicalize(config) hook for de-duplicating equivalent designs
  • optional perturb(anchor, rng, strength) hook for domain-aware local search
  • optional global_sampler(rng, n) hook for domain-aware global candidates
  • tree-ensemble surrogate with uncertainty from estimator disagreement
  • candidate-pool MACE selection instead of raw-space acquisition gradients
  • ask/tell API suitable for expensive external EDA evaluators

Install

For regular use, install the released package from PyPI:

python -m pip install mace-eda-bo

For local development, clone the repository and install it in editable mode:

cd mace-eda-bo
python -m pip install -e .[dev]

Minimal Example

from mace_eda_bo import MACEBO, DesignSpace

space = DesignSpace([
    {"name": "x", "type": "num", "lb": -5.0, "ub": 5.0},
    {"name": "n", "type": "int", "lb": 1, "ub": 8},
    {"name": "kind", "type": "cat", "categories": ["a", "b", "c"]},
    {"name": "flag", "type": "bool"},
])

opt = MACEBO(space, init_samples=8, seed=0, maximize=False)

for _ in range(40):
    cfg = opt.ask()
    y = (cfg["x"] - 1.5) ** 2 + (cfg["n"] - 3) ** 2
    opt.tell(cfg, y)

print(opt.best_config, opt.best_y)

For EDA flows, pass shell-backed evaluators outside the optimizer and call tell() with the measured metric.

Available surrogate plugins:

MACEBO(space, surrogate="extra_trees")
MACEBO(space, surrogate="random_forest")
MACEBO(space, surrogate="gaussian_process")
MACEBO(space, surrogate="tpe")

Domain-Aware Candidate Generation

For structured EDA spaces, many raw configurations may map to the same legal design. MACEBO accepts optional hooks so users can keep the optimizer generic while injecting domain-specific search behavior:

def legalize(cfg):
    return repair_to_legal_design(cfg)

def canonicalize(cfg):
    return tuple(sorted(legalize(cfg).items()))

def perturb(anchor, rng, strength):
    # Mutate only parameters that are effective for this design family.
    return domain_local_neighbor(anchor, rng, strength)

def global_sampler(rng, n):
    # Optional: draw global candidates from a domain-specific distribution.
    return [sample_domain_design(rng) for _ in range(n)]

opt = MACEBO(
    space,
    legalize=legalize,
    canonicalize=canonicalize,
    perturb=perturb,
    global_sampler=global_sampler,
    init_samples=96,
    local_fraction=0.35,
    kappa=2.5,
    initial_sampler="sobol",
    maximize=True,
)

The perturb hook is useful for trust-region style local search in effective design spaces, while global_sampler is optional and should be validated for the target problem because a poor global distribution can hurt early search.

Trace and Resume

opt = MACEBO(space, initial_sampler="sobol", seed=0)
cfg = opt.ask()

try:
    y = run_expensive_flow(cfg)
    opt.tell(cfg, y)
except RuntimeError as exc:
    opt.tell_failed(cfg, reason=str(exc))

opt.save_trace("trace.csv")

restored = MACEBO.from_trace("trace.csv", space, initial_sampler="sobol", seed=0)

Examples

python examples/chiplet_like.py
python examples/chiplet_benchmark.py
python examples/shell_evaluator_demo.py
python examples/flow_adapter_demo.py
python examples/multi_objective_archive.py
python examples/parego_demo.py
python examples/repeatability_check.py
python examples/analyze_pareto.py
mace-eda-bo chiplet-like --budget 50
mace-eda-bo benchmark-chiplet-like --budget 40 --seeds 0 1 2
mace-eda-bo benchmark --config configs/chiplet_like.json
mace-eda-bo benchmark --config configs/parego_chiplet_like.json

The chiplet-like example demonstrates legalize, canonicalize, equivalent-design de-duplication, and a throughput-like maximization loop. The benchmark example compares random search with several MACEBO surrogate plugins across multiple seeds and writes trace.csv, summary.csv, convergence.csv, and convergence_mean.csv. The shell evaluator demo shows the same interface you would use for OpenROAD/Yosys-style command-line flows: write config.json, run an external command, parse metrics.json, and keep per-run artifacts. The flow adapter demo also renders a per-run flow.tcl template before launching the external command. The multi-objective archive example tracks Pareto-optimal designs from raw EDA metrics without collapsing them into a weighted score. The ParEGO demo uses the existing single-objective MACEBO loop to explore a multi-objective Pareto front with changing scalarizations. The repeatability check example estimates metric noise from repeated evaluations and recommends absolute epsilon values for Pareto pruning. The Pareto analyzer reads pareto_front.csv, writes pareto_summary.csv with count, coverage, and 2D hypervolume metrics, and plots common metric trade-offs when matplotlib is available. The parego_chiplet_like config compares random search, scalar MACEBO, and ParEGO on a toy multi-objective chiplet-like benchmark. ParEGO supports weight_sampler="random" and weight_sampler="sobol"; Sobol weights give a more even coverage of objective preferences. ParEGO also supports normalization="online" and normalization="fixed"; fixed normalization uses user-provided objective_bounds to keep scalarization scales stable across the run.

Config-Driven Benchmarks

Benchmark configs are JSON by default:

{
  "problem": "chiplet_like",
  "budget": 40,
  "seeds": [0, 1, 2],
  "output_dir": "examples/output/chiplet_benchmark_config",
  "optimizers": [
    {"name": "random", "type": "random"},
    {
      "name": "macebo_extra_trees",
      "type": "macebo",
      "init_samples": 10,
      "candidate_pool_size": 512,
      "local_fraction": 0.6,
      "initial_sampler": "sobol",
      "surrogate": "extra_trees"
    }
  ]
}

Run:

mace-eda-bo benchmark --config configs/chiplet_like.json

When a benchmark is configured with multi-objective metrics, it also writes pareto_front.csv with non-dominated designs per optimizer and seed.

{
  "objectives": [
    {"name": "frequency_mhz", "direction": "max"},
    {"name": "timing_slack_ns", "direction": "max"},
    {"name": "area_um2", "direction": "min"},
    {"name": "power_mw", "direction": "min"}
  ]
}

Near-duplicate Pareto points can be pruned explicitly with absolute or relative tolerances. By default, no pruning is applied.

{
  "pareto_abs_eps": {
    "frequency_mhz": 5.0,
    "timing_slack_ns": 0.005,
    "area_um2": 1000.0,
    "power_mw": 1.0
  },
  "pareto_rel_eps": {
    "area_um2": 0.01,
    "power_mw": 0.01
  }
}

Absolute epsilon values can be estimated from repeated evaluations of the same design:

from mace_eda_bo import recommend_abs_epsilons

pareto_abs_eps = recommend_abs_epsilons(repeated_metrics, multiplier=3.0)

Evaluators

See docs/eda_flow_contract.md for the expected input/output contract for real Yosys/OpenROAD-style flows.

For real EDA flows, return an EvaluationResult instead of a bare float when you want traces to keep metrics, runtime, artifacts, or failure reasons:

from mace_eda_bo import EvaluationResult

def evaluate(config):
    try:
        metrics = run_openroad_flow(config)
    except RuntimeError as exc:
        return EvaluationResult.failed(str(exc), artifacts_dir="runs/design_001")

    score = metrics["frequency_mhz"] - 0.01 * metrics["area_um2"]
    return EvaluationResult.ok(
        score,
        metrics=metrics,
        artifacts_dir="runs/design_001",
        runtime_sec=metrics.get("runtime_sec"),
    )

Benchmark traces include metrics_json, artifacts_dir, and runtime_sec columns.

For command-line EDA tools, use ShellEvaluator:

from mace_eda_bo import ShellEvaluator

evaluator = ShellEvaluator(
    ["python", "flow.py", "--config", "{config_json}", "--out", "{run_dir}"],
    root_dir="runs/openroad",
    metrics_file="metrics.json",
    score_key="score",
    timeout_sec=3600,
)

result = evaluator.evaluate({"clock_period": 2.0, "utilization": 0.65})

Each run directory contains config.json, stdout.txt, stderr.txt, and the metrics file produced by the external command.

For template-driven Yosys/OpenROAD-style flows, use EDAFlowEvaluator:

from mace_eda_bo import EDAFlowEvaluator

evaluator = EDAFlowEvaluator(
    ["openroad", "flow.tcl"],
    root_dir="runs/openroad",
    template_texts={
        "flow.tcl": """
set clock_period_ns ${clock_period_ns}
set core_utilization ${core_utilization}
# write metrics to ${metrics_json}
"""
    },
    metrics_file="metrics.json",
    score_key="score",
    timeout_sec=3600,
)

Templates use ${name} placeholders. Available names include the config keys plus ${run_dir}, ${config_json}, and ${metrics_json}.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mace_eda_bo-0.1.2.tar.gz (33.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mace_eda_bo-0.1.2-py3-none-any.whl (32.3 kB view details)

Uploaded Python 3

File details

Details for the file mace_eda_bo-0.1.2.tar.gz.

File metadata

  • Download URL: mace_eda_bo-0.1.2.tar.gz
  • Upload date:
  • Size: 33.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for mace_eda_bo-0.1.2.tar.gz
Algorithm Hash digest
SHA256 210b4440e4341632487128fdbdd47a7a3ccf1ff46659977529984e0b9b3e7f6c
MD5 ee392ba373f38c2b8c8114738e2de67e
BLAKE2b-256 77e0036dd172c86c67f2b02179e9a9ddeffde69457f5d44fa61de2af441cbd50

See more details on using hashes here.

File details

Details for the file mace_eda_bo-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: mace_eda_bo-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 32.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for mace_eda_bo-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0e42878cb4093ac6f0c931cbd9b8600b80d50f77534449c4774c369bb73fa2dd
MD5 abf5e7538809db3c1b37a5508354231f
BLAKE2b-256 bc0a401b07e1cb122a6ceb4344d3917bf221820996e6caaf622bc4d614c92b86

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page