> ## Documentation Index
> Fetch the complete documentation index at: https://proto.evodesign.org/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MCMC Optimizer

> Markov chain Monte Carlo (Metropolis-Hastings): proposes mutations from the generators and stochastically accepts or rejects each to minimize the weighted constraint energy, with a simulated-annealing temperature schedule that shifts from broad exploration to local refinement over the run.

<div class="page-hero">
  <div className="block dark:hidden">
    <svg viewBox="0 0 720 432" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="MCMC optimizer: a Metropolis trace walking over steps beside the target density it samples" style={{width:"100%",height:"auto",display:"block"}}><defs><pattern id="gridmcmcL" width="22" height="22" patternUnits="userSpaceOnUse"><circle cx="2" cy="2" r="1.2" fill="#344649" fillOpacity="0.10" /></pattern><marker id="arrmcmcL" viewBox="0 0 10 10" refX="8.5" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 L3,5 z" fill="#768b8e" /></marker></defs><rect x="12" y="12" width="696" height="408" rx="16" fill="#f9fcfc" stroke="#dee9e8" strokeWidth="1.2" /><rect x="12" y="12" width="696" height="408" rx="16" fill="url(#gridmcmcL)" /><text x="360" y="56" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="13.5" fontWeight="600" fill="#1d2c2f" textAnchor="middle">each step:  propose → score → accept if ΔE ≤ 0, else with prob  e^(−ΔE / T)</text><path d="M112,150 L112,312 L662,312" fill="none" stroke="#c4d2d2" strokeWidth="1.4" /><text x="108" y="144" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="10.5" fontWeight="400" fill="#768b8e" textAnchor="start">energy</text><text x="106" y="316" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="10" fontWeight="400" fill="#768b8e" textAnchor="end">0</text><path d="M124,167.94 L132.59,208.02 L141.18,177.83 L149.77,156 L158.36,176.12 L166.95,203.03 L175.54,213.98 L184.13,224.69 L192.72,219.97 L201.31,210.95 L209.9,206.11 L218.49,216.12 L227.08,220.47 L235.67,247.36 L244.26,257.13 L252.85,233.02 L261.44,254.11 L270.03,254.87 L278.62,273.74 L287.21,289.64 L295.8,285.21 L304.39,252.84 L312.98,270.16 L321.57,252.15 L330.16,282.6 L338.75,272.48 L347.34,273.99 L355.93,297.3 L364.52,272.38 L373.11,279.2 L381.7,273.1 L390.3,276.3 L398.89,276.52 L407.48,289.77 L416.07,289.22 L424.66,294.51 L433.25,299.73 L441.84,287.24 L450.43,301.51 L459.02,299.11 L467.61,290.83 L476.2,292.89 L484.79,301.91 L493.38,307.15 L501.97,303.01 L510.56,304.55 L519.15,306.15 L527.74,309.73 L536.33,308.3 L544.92,310 L553.51,307.9 L562.1,307.36 L570.69,309.9 L579.28,310 L587.87,310 L596.46,310 L605.05,310 L613.64,310 L622.23,310 L630.82,310 L639.41,310 L648,310" fill="none" stroke="#046e7a" strokeWidth="2" strokeLinejoin="round" /><circle cx="648" cy="310" r="7" fill="#2f8f6b" /><text x="386" y="336" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="10.5" fontWeight="400" fill="#768b8e" textAnchor="middle">step  ·  high T explores, low T converges</text><path d="M261,392 l20,0" fill="none" stroke="#046e7a" strokeWidth="2.6" /><text x="288" y="396" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11" fontWeight="400" fill="#768b8e" textAnchor="start">energy</text><circle cx="412" cy="392" r="5.5" fill="#2f8f6b" /><text x="428" y="396" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11" fontWeight="400" fill="#768b8e" textAnchor="start">current state</text></svg>
  </div>

  <div className="hidden dark:block">
    <svg viewBox="0 0 720 432" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="MCMC optimizer: a Metropolis trace walking over steps beside the target density it samples" style={{width:"100%",height:"auto",display:"block"}}><defs><pattern id="gridmcmcD" width="22" height="22" patternUnits="userSpaceOnUse"><circle cx="2" cy="2" r="1.2" fill="#9eb4b2" fillOpacity="0.10" /></pattern><marker id="arrmcmcD" viewBox="0 0 10 10" refX="8.5" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 L3,5 z" fill="#7e9498" /></marker></defs><rect x="12" y="12" width="696" height="408" rx="16" fill="#0e1718" stroke="#2b3c3e" strokeWidth="1.2" /><rect x="12" y="12" width="696" height="408" rx="16" fill="url(#gridmcmcD)" /><text x="360" y="56" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="13.5" fontWeight="600" fill="#eef5f4" textAnchor="middle">each step:  propose → score → accept if ΔE ≤ 0, else with prob  e^(−ΔE / T)</text><path d="M112,150 L112,312 L662,312" fill="none" stroke="#3c4f51" strokeWidth="1.4" /><text x="108" y="144" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="10.5" fontWeight="400" fill="#9eb4b2" textAnchor="start">energy</text><text x="106" y="316" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="10" fontWeight="400" fill="#9eb4b2" textAnchor="end">0</text><path d="M124,167.94 L132.59,208.02 L141.18,177.83 L149.77,156 L158.36,176.12 L166.95,203.03 L175.54,213.98 L184.13,224.69 L192.72,219.97 L201.31,210.95 L209.9,206.11 L218.49,216.12 L227.08,220.47 L235.67,247.36 L244.26,257.13 L252.85,233.02 L261.44,254.11 L270.03,254.87 L278.62,273.74 L287.21,289.64 L295.8,285.21 L304.39,252.84 L312.98,270.16 L321.57,252.15 L330.16,282.6 L338.75,272.48 L347.34,273.99 L355.93,297.3 L364.52,272.38 L373.11,279.2 L381.7,273.1 L390.3,276.3 L398.89,276.52 L407.48,289.77 L416.07,289.22 L424.66,294.51 L433.25,299.73 L441.84,287.24 L450.43,301.51 L459.02,299.11 L467.61,290.83 L476.2,292.89 L484.79,301.91 L493.38,307.15 L501.97,303.01 L510.56,304.55 L519.15,306.15 L527.74,309.73 L536.33,308.3 L544.92,310 L553.51,307.9 L562.1,307.36 L570.69,309.9 L579.28,310 L587.87,310 L596.46,310 L605.05,310 L613.64,310 L622.23,310 L630.82,310 L639.41,310 L648,310" fill="none" stroke="#0a7e8c" strokeWidth="2" strokeLinejoin="round" /><circle cx="648" cy="310" r="7" fill="#2f8f6b" /><text x="386" y="336" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="10.5" fontWeight="400" fill="#9eb4b2" textAnchor="middle">step  ·  high T explores, low T converges</text><path d="M261,392 l20,0" fill="none" stroke="#0a7e8c" strokeWidth="2.6" /><text x="288" y="396" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11" fontWeight="400" fill="#9eb4b2" textAnchor="start">energy</text><circle cx="412" cy="392" r="5.5" fill="#2f8f6b" /><text x="428" y="396" fontFamily="Geist, ui-sans-serif, system-ui, -apple-system, sans-serif" fontSize="11" fontWeight="400" fill="#9eb4b2" textAnchor="start">current state</text></svg>
  </div>
</div>

<p class="entity-disclaimer">This optimizer is open source. Any third-party models, product names, or trademarks referenced are the property of their respective owners, and Proto is not affiliated with them.</p>

<hr class="entity-rule" />

<div class="tool-tab-bar entity-source-bar"><span class="tool-tab-wrap"><span class="tool-tab badge-source entity-source-tab"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6" /><polyline points="8 6 2 12 8 18" /></svg> Source</span></span></div>

<a href="https://github.com/evo-design/proto-language/blob/d3b7822f74ea64747cc751a3b2ab1aa6b799ac47/proto_language/optimizer/mcmc_optimizer.py#L160" target="_blank" class="tab-panel source-panel entity-source-panel">
  <div class="source-info">
    <img noZoom src="https://github.com/evo-design.png?size=40" class="source-avatar" width="36" height="36" />

    <span class="source-path">evo-design/proto-language<span class="source-subpath">/proto\_language/optimizer/mcmc\_optimizer.py</span></span>
  </div>

  <span class="panel-goto-btn source-goto-btn"><span><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" /></svg> View source</span></span>
</a>

<div class="entity-contributors"><span class="entity-contributors-label">Optimizer contributors</span><span class="entity-contributors-people"><a class="entity-contributor" href="https://github.com/dguo8412" target="_blank" rel="noopener" title="dguo8412: 6 commits"><img noZoom class="entity-contributor-avatar" src="https://avatars.githubusercontent.com/u/46211285?v=4&s=64" alt="" loading="lazy" /><span class="entity-contributor-login">dguo8412</span></a></span></div>
Metropolis-Hastings MCMC optimizer for constraint-driven sequence optimization.

This optimizer implements Metropolis-Hastings sampling with simulated annealing
to optimize sequences against constraint-based energy functions. It uses mutation
generators as proposal distributions and accepts/rejects proposals based on energy
changes and temperature.

At each step, the optimizer generates `num_results x proposals_per_result`
proposals by mutating each of the K sequences `proposals_per_result` times.
Each trajectory (result index) is independent. For each trajectory, the best proposal
(lowest energy) is selected, then MH acceptance is applied to decide whether to
accept or reject that proposal. If rejected, the trajectory keeps its previous state.

<Note>
  * Typically used with mutation generators (`category="mutation"`)
  * Uses Metropolis-Hastings acceptance: always accepts improvements,
    accepts worse proposals with probability exp(-ΔE/T)
  * Simulated annealing via configurable `temperature_schedule`
  * Lower energy scores are better (minimization objective)
  * When `proposals_per_result > 1`, generates multiple proposals per
    trajectory, selects the best one, then applies a single MH accept/reject decision
</Note>

## How It Works

MCMC walks a single trajectory: each step proposes a mutation, then accepts it outright if it lowers the energy or, when worse, with a temperature-dependent probability that cools over the run.

Each step replicates every tracked sequence into a pool of `P` proposals (`P = proposals_per_result`), mutates them with a randomly chosen generator, scores the pool, and takes the lowest-energy proposal `x′`. A Metropolis-Hastings test then decides whether to move there:

```
α = min(1, exp(−(E(x′) − E(x)) / T))          accept x′ when  u ~ U(0,1) < α
T(t) = T_max · (T_min / T_max)^((t−1)/(N−1))   temperature anneals T_max → T_min
```

Improving moves (`ΔE ≤ 0`) are always accepted; a worse move is still taken with probability `exp(−ΔE/T)`, so hot early steps explore and cold late steps exploit. An infeasible proposal (`E = ∞`) is always rejected, and `num_results` independent trajectories run in parallel.

## API Reference

<div class="api-model-section api-model-static api-config-section">
  <div class="api-model-header"><span class="api-model-badge api-config-badge">Config</span><span class="api-model-name">MCMCOptimizerConfig</span><a href="https://github.com/evo-design/proto-language/blob/d3b7822f74ea64747cc751a3b2ab1aa6b799ac47/proto_language/optimizer/mcmc_optimizer.py#L56" target="_blank" class="func-table-btn func-source-btn api-model-source"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6" /><polyline points="8 6 2 12 8 18" /></svg> Source</a></div>

  Configuration object for MCMCOptimizer.

  This class defines configuration parameters for the Metropolis-Hastings MCMC
  optimizer, which explores sequence space through iterative mutation with
  probabilistic acceptance based on energy improvements.

  <Note>
    * The field default is `None` (inherits the program-level `num_results`).
    * When `num_results=1`, behaves like standard single-chain MCMC.
    * When `num_results > 1`, maintains that many independent trajectories and
      generates `proposals_per_result` (default: 1) proposals per result sequence each step.
  </Note>

  <ParamField path="num_steps" type="integer" required>
    Number of Metropolis-Hastings steps. Each step proposes, evaluates, and accept/reject samples.
  </ParamField>

  <ParamField path="num_results" type="integer">
    Independent MCMC trajectories run in parallel; each yields one candidate. Overrides program count.
  </ParamField>

  <ParamField path="proposals_per_result" type="integer" default="1">
    Proposals per trajectory each step; the best by energy is chosen, then accept/reject is applied.
  </ParamField>

  <ParamField path="max_temperature" type="number" default="1.0">
    Starting temperature for simulated annealing; higher accepts worse proposals more readily.
  </ParamField>

  <ParamField path="min_temperature" type="number" default="0.001">
    Ending dimensionless temperature for simulated annealing; must be greater than 0 and below the max.
  </ParamField>

  <ParamField path="temperature_schedule" type="enum" default="exponential">
    Annealing schedule from max to min temperature.

    Options: `constant`, `cosine`, `exponential`, `hinge`, `linear`, `quadratic`
  </ParamField>

  <ParamField path="seed" type="integer">
    Random seed for reproducible optimization, generator, and constraint tool streams.
  </ParamField>

  <ParamField path="tracking_interval" type="integer" default="1">
    Save history and log progress every N steps. Step 0 and final step always saved.
  </ParamField>

  <ParamField path="track_proposals" type="boolean" default="False">
    Save granular per-proposal results (accept/reject) in history snapshots.
  </ParamField>

  <ParamField path="verbose" type="boolean" default="False">
    Emit per-step debug information about proposals, scores, and acceptance through the logger.
  </ParamField>
</div>

## Usage

```python python icon="python" theme={null}
>>> constructs = [Construct([segment1, segment2])]
>>> config = MCMCOptimizerConfig(num_results=1, num_steps=100, max_temperature=0.5, min_temperature=0.001)
>>> mcmc = MCMCOptimizer(
...     constructs=constructs, generators=[mutation_gen], constraints=[gc_constraint], config=config
... )
>>> mcmc.run()
>>> final_sequences = mcmc.constructs[0].joined_sequences
```

## Metadata

| Property               | Value           |
| ---------------------- | --------------- |
| Key                    | `mcmc`          |
| Class                  | `MCMCOptimizer` |
| Targets Single Segment | `False`         |
| Uses GPU               | `False`         |
