mirror of
https://github.com/lightningnetwork/lnd.git
synced 2026-08-20 13:27:27 +02:00
In this commit, we write up exp-012 and exp-002b on the findings page, and put a corrections callout above everything else on it. exp-012 gets §08. Every number we've published is a cold-start number, so the section walks the four arms that finally tested the other regime: the warmup curves (lnd's disadvantage grows 4.7x to 11.9x across a mainnet batch, the champions are already cheap on payment one, atomic1 is the only router that measurably learns), the depletion mistake that the snapshot and restore control fixed, the three failure modes under a maximally stale cache (lnd thrashes, the champions abandon, atomic1 shrugs at a 0.012 probability floor), the staleness null that indicts our own churn engine, and the vantage transfer result. atomic1's +0.428 at p=.002 is the first significant win over a champion here, so it gets a stat tile, and the note says plainly that the negative is about probe-warming rather than weight-serving, since no arm can buy knowledge without spending liquidity. exp-002b gets §09. Seven bimodal scales including the environment-matched one, and none of them beats lnd's own apriori default. How it fails is the part worth reading: a better prior raises success while more than doubling attempts, because findPath takes the amount as a fixed argument and the estimator can't change what lnd retries. The corrections callout is §00, unnumbered as a section but linked first in the TOC, and it retracts three claims we made about ourselves: the bimodal prior was in the harness prompt all along, the evolved prior constants fit sim_liquidity.go's generator (so the mainnet tier is real topology and policies with our liquidity), and lnd's decay never fires on the static tiers. The one flatly contradicted sentence in §04 now carries a retraction marker pointing at it. A research site that corrects itself where readers can see it is more credible, not less. Downstream sections renumber to §10 and §11, the timeline picks up two entries, and the masthead and index status lines move to exp-012 and exp-002b closed with exp-013 live.
524 lines
24 KiB
HTML
524 lines
24 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Evolving Lightning's next routing algorithm — lnd × GEPA</title>
|
||
<meta name="description" content="An LLM-driven evolutionary search over Lightning routing algorithms, run against lnd's real pathfinding stack in an in-process payment simulator. What it found, and how." />
|
||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300..600;1,6..72,300..500&family=Spline+Sans+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
||
<link rel="stylesheet" href="style.css" />
|
||
</head>
|
||
<body>
|
||
|
||
<a class="skip" href="#main">Skip to content</a>
|
||
|
||
<header class="site-header">
|
||
<div class="shell">
|
||
<a class="wordmark" href="index.html">lnd<span class="x">×</span>GEPA</a>
|
||
<nav class="site-nav">
|
||
<a href="index.html" aria-current="page">overview</a>
|
||
<a href="findings.html">findings</a>
|
||
<a href="drift.html">drift</a>
|
||
<a href="#run">live run</a>
|
||
</nav>
|
||
</div>
|
||
</header>
|
||
|
||
<main id="main">
|
||
|
||
<!-- ================= MASTHEAD ================= -->
|
||
<div class="shell masthead">
|
||
<div class="eyebrow">
|
||
Research log<span class="sep">/</span>Lightning Network pathfinding<span class="sep">/</span>July 2026
|
||
</div>
|
||
<h1>Evolving Lightning's <em>next</em> routing algorithm</h1>
|
||
<div class="masthead-grid">
|
||
<p class="standfirst">
|
||
We pointed an LLM-driven evolutionary search at lnd's real pathfinding
|
||
stack, inside a simulator that hides channel liquidity the way the network
|
||
does. <strong>Tuning its parameters found nothing. Replacing the algorithm
|
||
found a lot.</strong>
|
||
</p>
|
||
<div class="glance">
|
||
<div class="g hi">
|
||
<span class="l">attempts per payment<br>mainnet, vs lnd's 19.8</span>
|
||
<span class="v">2.3</span>
|
||
</div>
|
||
<div class="g">
|
||
<span class="l">objective, mainnet<br>vs lnd's 0.694</span>
|
||
<span class="v">0.791</span>
|
||
</div>
|
||
<div class="g">
|
||
<span class="l">evolved lines of Go<br>from a 300-line seed</span>
|
||
<span class="v">1,525</span>
|
||
</div>
|
||
<div class="cap">best evolved router (mx_c3) against lnd's production stack</div>
|
||
</div>
|
||
</div>
|
||
<div class="byline">
|
||
<span>method <b>GEPA reflective evolution</b></span>
|
||
<span>reflection LM <b>gpt-5.6-sol</b></span>
|
||
<span>evaluator <b>cmd/routesim</b></span>
|
||
<span>experiments <b>exp-001 … exp-013</b></span>
|
||
<span>exp-012 and exp-002b <b>closed</b> · live <b>exp-013 · atomic1 on the mixed corpus</b></span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ================= 01 · FINDINGS ================= -->
|
||
<section id="result">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">01</div>
|
||
<h2>What the search found</h2>
|
||
<p class="sec-sub">
|
||
Every number below is held out. The closing check ran on a real mainnet
|
||
graph snapshot — lnd's home turf, and a topology the evolved routers had
|
||
never seen.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="keyrow wide">
|
||
<div class="key hi">
|
||
<span class="kn">8.6<span class="u">×</span></span>
|
||
<div class="kl">
|
||
fewer HTLC attempts per payment than lnd on the real mainnet graph, at
|
||
the same success rate
|
||
</div>
|
||
<div class="kf">2.3 vs 19.8 attempts · exp-009</div>
|
||
</div>
|
||
<div class="key">
|
||
<span class="kn">4<span class="u">of 4</span></span>
|
||
<div class="kl">
|
||
held-out tiers the evolved routers lead: sealed synthetic test,
|
||
out-of-distribution topologies, mainnet snapshot, drifting liquidity
|
||
</div>
|
||
<div class="kf">the fourth arrived with exp-008</div>
|
||
</div>
|
||
<div class="key">
|
||
<span class="kn">0</span>
|
||
<div class="kl">
|
||
parameter settings, out of 400 evaluations of estimator and cost
|
||
knobs, that beat the lnd defaults
|
||
</div>
|
||
<div class="kf">exp-002 · the negative result that redirected the project</div>
|
||
</div>
|
||
</div>
|
||
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Attempts per payment on a mainnet snapshot</span>
|
||
<span class="fig-n">Fig. 1 · lower is better</span>
|
||
</div>
|
||
<div class="plot resp" id="fig-attempts"></div>
|
||
<figcaption>
|
||
12,161 nodes, 39,659 channels, 100 payments from the network's
|
||
highest-degree node. Success rates are close — lnd 0.790, seed 0.820,
|
||
evolved 0.810 — so the whole difference lands in <b>how much probing it
|
||
takes to get there</b>. This is the tier lnd should win: its defaults were
|
||
tuned for this graph, while the evolved routers were bred entirely on
|
||
synthetic topologies.
|
||
</figcaption>
|
||
</figure>
|
||
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Composite objective, by router and held-out tier</span>
|
||
<span class="fig-n">Fig. 2 · higher is better</span>
|
||
</div>
|
||
<div class="plot resp" id="fig-champions"></div>
|
||
<div class="legend">
|
||
<span class="item"><i style="background:#a83f22"></i> evolved by GEPA</span>
|
||
<span class="item"><i style="background:#8a8175"></i> baseline (lnd, or hand-written)</span>
|
||
</div>
|
||
<figcaption>
|
||
Objective is <span class="mono">success − 0.01·min(extra attempts, 15) −
|
||
0.00002·min(fee ppm, 5000)</span>. The two evolved routers lead on all
|
||
three tiers. On synthetic corpora the gap is mostly success rate; on the
|
||
real graph it is almost entirely efficiency. Reruns are bit-identical
|
||
(stdev 0.00000 over five repeats), and both champions were audited clean
|
||
of simulator exploits.
|
||
</figcaption>
|
||
<details class="tableview">
|
||
<summary>Table view</summary>
|
||
<div class="tw">
|
||
<table class="data">
|
||
<caption>Composite objective. Combined is the mean of the two synthetic held-out sets.</caption>
|
||
<thead>
|
||
<tr>
|
||
<th>router</th>
|
||
<th class="num">mainnet</th>
|
||
<th class="num">hard sealed test</th>
|
||
<th class="num">out-of-distribution</th>
|
||
<th class="num">combined</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>lnd production stack<span class="sub">Dijkstra + mission control</span></td>
|
||
<td class="num" data-l="mainnet">0.694</td><td class="num" data-l="hard sealed test">0.309</td>
|
||
<td class="num" data-l="out-of-distribution">0.357</td><td class="num" data-l="combined">0.333</td>
|
||
</tr>
|
||
<tr>
|
||
<td>hand-written seed<span class="sub">~300 lines, cheapest path + blacklist</span></td>
|
||
<td class="num" data-l="mainnet">0.762</td><td class="num" data-l="hard sealed test">0.530</td>
|
||
<td class="num" data-l="out-of-distribution">0.487</td><td class="num" data-l="combined">0.509</td>
|
||
</tr>
|
||
<tr>
|
||
<td>hb1<span class="sub">evolved, 872 lines</span></td>
|
||
<td class="num" data-l="mainnet">0.790</td><td class="num" data-l="hard sealed test">0.586</td>
|
||
<td class="num" data-l="out-of-distribution">0.545</td><td class="num" data-l="combined">0.565</td>
|
||
</tr>
|
||
<tr class="best">
|
||
<td>mx_c3<span class="sub">evolved, 1,525 lines</span></td>
|
||
<td class="num" data-l="mainnet">0.791</td><td class="num" data-l="hard sealed test">0.583</td>
|
||
<td class="num" data-l="out-of-distribution">0.581</td><td class="num" data-l="combined">0.582</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</details>
|
||
</figure>
|
||
|
||
<div class="prose">
|
||
<p>
|
||
The headline is not the size of the win, it is <em>where the win came
|
||
from</em>. A 400-evaluation search over lnd's own pathfinding knobs — which
|
||
probability estimator, how much a failed attempt should virtually cost, the
|
||
floor on acceptable route probability — produced no setting that beat the
|
||
shipped defaults on validation. The defaults are locally robust; the
|
||
headroom is not in the knobs.
|
||
</p>
|
||
<p>
|
||
Meanwhile a deliberately naive 300-line router with a <em>different
|
||
paradigm</em> beat lnd's full production stack by 39% on the objective,
|
||
winning or tying every example. Handing that seed to the optimizer, and
|
||
letting it rewrite the whole algorithm rather than adjust its settings,
|
||
produced routers that beat both. What they invented — liquidity intervals
|
||
instead of decaying penalties — is the interesting part.
|
||
</p>
|
||
<p>
|
||
<a class="link" href="findings.html">Read the full findings →</a>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= 02 · METHOD ================= -->
|
||
<section id="method">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">02</div>
|
||
<h2>How the search works</h2>
|
||
<p class="sec-sub">
|
||
A candidate is a whole routing algorithm in Go. Every proposal is
|
||
compiled into a simulator and made to actually pay.
|
||
</p>
|
||
</div>
|
||
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">One turn of the evolutionary loop</span>
|
||
<span class="fig-n">Fig. 3</span>
|
||
</div>
|
||
<div class="schema">
|
||
<svg viewBox="0 0 1000 252" role="img" aria-label="The GEPA loop: propose, compile, simulate, score, reflect, then back to propose.">
|
||
<!-- stage boxes -->
|
||
<g>
|
||
<rect x="1" y="26" width="170" height="92" fill="#fbfaf6" stroke="#cbc4b2" stroke-width="1"/>
|
||
<text class="s-num" x="14" y="46">01</text>
|
||
<text class="s-title" x="14" y="66" font-size="14">propose</text>
|
||
<text class="s-body" x="14" y="86">the reflection LM</text>
|
||
<text class="s-body" x="14" y="102">rewrites the router</text>
|
||
</g>
|
||
<path d="M 179 72 h 20 m -6 -5 l 6 5 l -6 5" fill="none" stroke="#b3ab97" stroke-width="1.2"/>
|
||
<g>
|
||
<rect x="207" y="26" width="170" height="92" fill="#fbfaf6" stroke="#cbc4b2" stroke-width="1"/>
|
||
<text class="s-num" x="220" y="46">02</text>
|
||
<text class="s-title" x="220" y="66" font-size="14">compile</text>
|
||
<text class="s-body" x="220" y="86">go build −overlay drops</text>
|
||
<text class="s-body" x="220" y="102">it into the simulator</text>
|
||
</g>
|
||
<path d="M 385 72 h 20 m -6 -5 l 6 5 l -6 5" fill="none" stroke="#b3ab97" stroke-width="1.2"/>
|
||
<g>
|
||
<rect x="413" y="26" width="170" height="92" fill="#fbfaf6" stroke="#cbc4b2" stroke-width="1"/>
|
||
<text class="s-num" x="426" y="46">03</text>
|
||
<text class="s-title" x="426" y="66" font-size="14">simulate</text>
|
||
<text class="s-body" x="426" y="86">it pays, against hidden</text>
|
||
<text class="s-body" x="426" y="102">channel liquidity</text>
|
||
</g>
|
||
<path d="M 591 72 h 20 m -6 -5 l 6 5 l -6 5" fill="none" stroke="#b3ab97" stroke-width="1.2"/>
|
||
<g>
|
||
<rect x="619" y="26" width="170" height="92" fill="#fbfaf6" stroke="#cbc4b2" stroke-width="1"/>
|
||
<text class="s-num" x="632" y="46">04</text>
|
||
<text class="s-title" x="632" y="66" font-size="14">score</text>
|
||
<text class="s-body" x="632" y="86">success, minus attempt</text>
|
||
<text class="s-body" x="632" y="102">and fee penalties</text>
|
||
</g>
|
||
<path d="M 797 72 h 20 m -6 -5 l 6 5 l -6 5" fill="none" stroke="#b3ab97" stroke-width="1.2"/>
|
||
<g>
|
||
<rect x="825" y="26" width="170" height="92" fill="#fbfaf6" stroke="#cbc4b2" stroke-width="1"/>
|
||
<text class="s-num" x="838" y="46">05</text>
|
||
<text class="s-title" x="838" y="66" font-size="14">reflect</text>
|
||
<text class="s-body" x="838" y="86">keep it only if it holds</text>
|
||
<text class="s-body" x="838" y="102">up across the splits</text>
|
||
</g>
|
||
|
||
<!-- feedback return path -->
|
||
<path d="M 910 118 V 176 H 86 V 124 m -5 6 l 5 -6 l 5 6"
|
||
fill="none" stroke="#a83f22" stroke-width="1.4"/>
|
||
<text class="s-label-strong" x="498" y="199" text-anchor="middle" fill="#a83f22">
|
||
per-attempt failure traces are the feedback
|
||
</text>
|
||
<text class="s-body" x="498" y="220" text-anchor="middle">
|
||
which hop died, at what amount, with which BOLT error — so the next mutation is informed, not random
|
||
</text>
|
||
</svg>
|
||
</div>
|
||
<div class="scrollhint">scroll the diagram sideways →</div>
|
||
<figcaption>
|
||
The optimizer never sees hidden balances. A candidate gets the public
|
||
gossip graph, its own channel balances, and the errors its attempts
|
||
provoke — the same information a real Lightning sender has.
|
||
</figcaption>
|
||
</figure>
|
||
|
||
<div class="prose">
|
||
<h3>The simulator runs lnd's real code</h3>
|
||
<p>
|
||
<code>routing/sim_graph.go</code> is an in-memory Lightning network with
|
||
hidden per-channel balances and per-direction policies: base and
|
||
proportional fees, CLTV deltas, min and max HTLC. It implements lnd's own
|
||
<code>Graph</code> interface, so lnd's production pathfinding and mission
|
||
control run against it unmodified — which is what makes the baseline
|
||
honest.
|
||
</p>
|
||
<p>
|
||
Forwarding enforces real BOLT semantics. An attempt that asks too little
|
||
fee gets <code>FeeInsufficient</code>; one that asks for more than a hop
|
||
holds gets <code>TemporaryChannelFailure</code>, the liquidity miss that
|
||
all of routing is really about. Balances move on success and unwind on
|
||
failure. Topologies are synthetic (line, grid, hub-and-spoke, small-world,
|
||
scale-free) or loaded from a mainnet <code>describegraph</code> snapshot,
|
||
and hidden balances follow a half, uniform, or <em>bimodal</em> model — the
|
||
last one hugging one end of each channel, which is both realistic and the
|
||
hard case.
|
||
</p>
|
||
<p>
|
||
It is fast enough to be an inner loop: ten payments on a 200-node network
|
||
in about 0.3 seconds including process startup, so thousands of
|
||
evaluations are cheap.
|
||
</p>
|
||
|
||
<h3>A candidate is an algorithm, not a config</h3>
|
||
<p>
|
||
The evolvable unit is a Go file behind a paradigm-free interface: gossip
|
||
view, local balances, and per-attempt feedback in; a route out. GEPA
|
||
rewrites that file, <code>go build -overlay</code> compiles the rewrite into
|
||
the simulator, and the evaluator scores it on a corpus split into train,
|
||
validation and sealed test. Nothing in the contract mentions Dijkstra,
|
||
mission control, or probability estimators. Those become background
|
||
knowledge the reflection prompt may draw on, keep, reshape, or discard.
|
||
</p>
|
||
|
||
<div class="note">
|
||
<h4>the sandbox held</h4>
|
||
<p>
|
||
An independent audit found that the graph session handed candidates the
|
||
concrete simulator graph, type-assertable back into a read of hidden
|
||
balances or an outright rewrite of ground-truth liquidity — a
|
||
perfect-score reward hack using no banned identifiers. It was sealed the
|
||
same day, and every in-flight candidate was checked against it: zero
|
||
hits. No result on this site was produced through that hole.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= 03 · CORPUS ================= -->
|
||
<section id="corpus">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">03</div>
|
||
<h2>The scenarios it is scored against</h2>
|
||
<p class="sec-sub">
|
||
<span class="mono" id="c-files">—</span> scenario files,
|
||
<span class="mono" id="c-scen">—</span> payments,
|
||
split <span class="mono" id="c-split">—</span>. Validation picks the
|
||
incumbent; the test split stays sealed until a champion is declared.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="figgrid">
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Topology</span>
|
||
<span class="fig-n">files</span>
|
||
</div>
|
||
<div class="bars" id="bars-topology"></div>
|
||
</figure>
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Hidden liquidity model</span>
|
||
<span class="fig-n">files</span>
|
||
</div>
|
||
<div class="bars" id="bars-liquidity"></div>
|
||
<figcaption>
|
||
Bimodal is the hard regime: funds parked at one end of each channel,
|
||
so capacity tells you almost nothing about what will actually pass.
|
||
</figcaption>
|
||
</figure>
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Payment amount</span>
|
||
<span class="fig-n">scenarios, satoshis</span>
|
||
</div>
|
||
<div class="bars" id="bars-amount"></div>
|
||
</figure>
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Shard budget</span>
|
||
<span class="fig-n">scenarios, max parts</span>
|
||
</div>
|
||
<div class="bars" id="bars-parts"></div>
|
||
</figure>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= 04 · LIVE RUN ================= -->
|
||
<section id="run">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">04</div>
|
||
<h2>The run behind the drift verdict</h2>
|
||
<p class="sec-sub">
|
||
Telemetry from the optimizer, exported straight out of the GEPA run
|
||
directory. <span class="mono">code_drift1</span> has since finished all 400
|
||
evaluations, and so have exp-010's three splitting arms — all of them beaten
|
||
by the champions
|
||
(<a class="link" href="findings.html#splitting">the verdict</a>). exp-010b's
|
||
two atomic-arena arms have since closed the same way — the champion's fifth
|
||
hold, against an arena built to charge its probe ladder honestly
|
||
(<a class="link" href="findings.html#atomic">the atomic verdict</a>) — and so
|
||
has exp-012, which found no hot-cache regime anywhere but did find the one
|
||
change this work argues for upstream
|
||
(<a class="link" href="findings.html#coldcache">cold cache, hot load</a>).
|
||
<span class="mono">exp-013</span>, an atomic1 continuation on the mixed
|
||
corpus, takes this slot next.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="runbar">
|
||
<span><span class="dot"></span>run <b id="rb-run">—</b></span>
|
||
<span>reflection <b id="rb-lm">—</b></span>
|
||
<span>mode <b id="rb-mode">—</b></span>
|
||
<span>budget <b>400 evals</b></span>
|
||
</div>
|
||
|
||
<div class="statline wide" id="run-stats"></div>
|
||
|
||
<div class="prose" style="margin-bottom:34px">
|
||
<p>
|
||
<code>code_drift1</code> was the first run in a moving world. Its
|
||
predecessor, <code>code_gen2</code>, showed that more evaluations of a
|
||
static environment buy nothing — three independently bred routers landed
|
||
inside a band 0.014 wide (the
|
||
<a class="link" href="findings.html#ceiling">paradigm ceiling</a>). So this
|
||
run changed the environment instead of the budget: a virtual clock and
|
||
background senders moving hidden liquidity between our payments, and the
|
||
question of whether time-awareness re-evolves once knowledge genuinely goes
|
||
stale. <strong>It did — and it still lost.</strong> The winner stamps every
|
||
belief and halves its confidence every 35 virtual minutes, and the time-less
|
||
champions beat it on all four held-out tiers, drift included. The mechanism,
|
||
the numbers and the caveats are on the
|
||
<a class="link" href="drift.html">drift page</a>.
|
||
</p>
|
||
</div>
|
||
|
||
<figure class="wide" style="margin-top:0">
|
||
<div class="fig-head">
|
||
<span class="fig-t">Score over iterations</span>
|
||
<span class="fig-n">Fig. 4 · minibatch objective</span>
|
||
</div>
|
||
<div class="plot" id="score-chart"></div>
|
||
<div class="scrollhint">scroll the chart sideways →</div>
|
||
<div class="legend">
|
||
<span class="item"><i class="line" style="background:#a83f22"></i> best kept</span>
|
||
<span class="item"><i class="line" style="background:#2f6ea8"></i> proposed</span>
|
||
<span class="item"><i class="dash"></i> seed baseline</span>
|
||
</div>
|
||
<figcaption>
|
||
These are per-minibatch scores on the training split, not held-out
|
||
numbers — they are how GEPA decides what to keep, and they run
|
||
optimistically high. Every comparison in section 01 comes from separate
|
||
held-out runs instead.
|
||
</figcaption>
|
||
</figure>
|
||
|
||
<figure class="wide">
|
||
<div class="fig-head">
|
||
<span class="fig-t">Candidate lineage</span>
|
||
<span class="fig-n">Fig. 5 · select a candidate</span>
|
||
</div>
|
||
<div class="plot dag" id="lineage-dag"></div>
|
||
<figcaption>
|
||
Each node is one compiled, scored router. Accepted candidates stay on the
|
||
frontier and can be mutated further; rejects are dead ends. The scores are
|
||
per-minibatch and each is measured on a different subset, so a rejected
|
||
candidate can carry a higher number than the incumbent without being
|
||
better.
|
||
</figcaption>
|
||
</figure>
|
||
|
||
<div class="panels">
|
||
<div class="panel">
|
||
<div class="fig-head">
|
||
<span class="fig-t">Candidate detail</span>
|
||
<span class="fig-n" id="detail-sub">—</span>
|
||
</div>
|
||
<div id="cand-detail"></div>
|
||
</div>
|
||
<div class="panel">
|
||
<div class="fig-head">
|
||
<span class="fig-t">What the mutation changed</span>
|
||
<span class="fig-n">line diff</span>
|
||
</div>
|
||
<div class="selects">
|
||
<label>base <select id="diff-a"></select></label>
|
||
<span>→</span>
|
||
<label>candidate <select id="diff-b"></select></label>
|
||
</div>
|
||
<pre class="diff" id="diff-view"></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="shell">
|
||
<div class="readnext">
|
||
<div class="k">read next</div>
|
||
<a class="big" href="findings.html">Findings: what the evolved routers kept, dropped, and invented</a>
|
||
<p>
|
||
The definitive write-up — the paradigm result, the champion scores, an
|
||
anatomy of the evolved algorithms against lnd's, the ceiling three separate
|
||
lineages ran into, three corrections to our own record, and the process lessons
|
||
from fourteen experiments.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
</main>
|
||
|
||
<div class="shell">
|
||
<footer class="site-footer">
|
||
<span>lnd × GEPA — Lightning routing evolution</span>
|
||
<span id="foot-run">run data loading…</span>
|
||
</footer>
|
||
</div>
|
||
|
||
<script src="app.js"></script>
|
||
</body>
|
||
</html>
|