<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Yuhan Chi</title>
  <link href="https://yuhanchi.github.io/feed.xml" rel="self"/>
  <link href="https://yuhanchi.github.io/"/>
  <updated>2026-10-19T16:28:47+08:00</updated>
  <id>https://yuhanchi.github.io/</id>
  <author><name>Yuhan Chi</name></author>
  <entry>
    <title>Choose the Noise, Keep the Flow</title>
    <link href="https://yuhanchi.github.io/writing/choose-the-noise/"/>
    <id>https://yuhanchi.github.io/writing/choose-the-noise/</id>
    <updated>2026-10-18T00:00:00+08:00</updated><summary>A gentle survey of noise-space policy steering: the VAE connection, five ways to carry value into noise space, a small 2D experiment, and the limits of a frozen decoder.</summary>
    <content type="html">&lt;p&gt;A recent survey by Nahim, Khan, and Ju, &lt;a href=&quot;https://arxiv.org/abs/2610.16275&quot;&gt;A Survey of Flow Matching in Reinforcement Learning&lt;/a&gt; (TMLR, 2026), organizes the field along two axes: &lt;em&gt;what&lt;/em&gt; the flow models (actions, critics, dynamics) and &lt;em&gt;where&lt;/em&gt; the RL signal enters (energy-weighted regression, policy gradients through the ODE, GRPO-style objectives). It is a useful map. I wanted to look more closely at one family that is not brought together as a group in that survey.&lt;/p&gt;

&lt;p&gt;At the center are methods that leave the velocity field untouched. They keep a pretrained flow or diffusion policy frozen and train a small network that decides &lt;strong&gt;which noise to feed it&lt;/strong&gt;. Given a state \(s\), a proposer picks a point \(w\) in noise space, and the frozen generator turns \(w\) into an action. Imagine a robot policy that sometimes reaches around an obstacle on the left and sometimes on the right. Steering the noise changes how often it chooses each route, while reusing the generator that produces the movements.&lt;/p&gt;

&lt;p&gt;The survey already covers an important relative. Its offline section discusses ReFORM (Zhang et al., 2026), which manipulates noise inside a bounded support so that the composed policy stays within the learned behavior model’s support. Its discussion of “freezing the flow and learning a correction” covers policies that &lt;em&gt;edit the action after it is generated&lt;/em&gt;. DSRL (Wagenmaker et al., 2025) and related methods that &lt;em&gt;choose the input&lt;/em&gt; instead of editing the output are absent. This post follows that thread, including a few neighbors that also train the decoder or learn from corrections rather than rewards.&lt;/p&gt;

&lt;p&gt;The post makes two points and then checks them on a small example.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A &lt;strong&gt;VAE-style inference view&lt;/strong&gt; connects the methods. The noise proposer plays the role of an encoder and the frozen generator that of a decoder. For a KL-regularized objective, this becomes an exact variational identity, with value taking the place of reconstruction quality. Other methods share the architecture without optimizing that same objective.&lt;/li&gt;
  &lt;li&gt;The most useful question to ask of each method is &lt;strong&gt;where RL takes effect&lt;/strong&gt;. Action-space data can train a critic directly, but the proposer lives in noise space. Each method is defined largely by how it carries value from one space to the other.&lt;/li&gt;
  &lt;li&gt;A &lt;strong&gt;two-dimensional experiment&lt;/strong&gt; (Section 4) trains the same noise proposer with five different ways of carrying value, so one can watch the noise move and the actions follow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;This post is also available as a &lt;a href=&quot;/files/choose-the-noise.pdf&quot;&gt;PDF&lt;/a&gt;, with numbered equations, stated propositions, and all tables expanded.&lt;/em&gt;&lt;/p&gt;

&lt;figure&gt;
  &lt;a href=&quot;/assets/img/posts/choose-the-noise/vae-correspondence.svg&quot; title=&quot;Open scalable figure&quot;&gt;&lt;img src=&quot;/assets/img/posts/choose-the-noise/vae-correspondence.png&quot; alt=&quot;Two aligned pipelines. (a) A VAE: x, encoder, latent z, decoder, reconstruction. (b) Noise-space RL: state s, proposer, noise w, frozen flow, value Q over beta, with s also feeding the flow. A shared N(0, I) prior sits between the two latents, linked to each by a KL term.&quot; width=&quot;1416&quot; height=&quot;506&quot; loading=&quot;lazy&quot; /&gt;&lt;/a&gt;
  &lt;figcaption&gt;&lt;strong&gt;Figure 1.&lt;/strong&gt; The shared encoder–decoder pattern. (a) A VAE trains an encoder and a decoder jointly to reconstruct its input. (b) In noise-space RL, a proposer \(q_\phi\) chooses the noise \(w\) for a state \(s\), and a pretrained, frozen flow \(\psi_\theta\) decodes it into an action. Both latents are pulled toward the same prior \(\mathcal{N}(0, I)\) by a KL term. The decoder in (b) produces an action rather than a reconstruction, and value \(Q/\beta\) takes the place of the reconstruction term. The correspondence is between objectives (Section 2), not between generative models.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;1-setup-and-notation&quot;&gt;1. Setup and notation&lt;/h2&gt;

&lt;p&gt;A flow-matching policy learns a velocity field \(v_\theta(x, t, s)\) that transports Gaussian noise at time \(t = 0\) to actions at \(t = 1\). To act, one draws \(w \sim \mathcal{N}(0, I)\) and integrates \(\dot x_t = v_\theta(x_t, t, s)\) from \(x_0 = w\), usually with a few Euler steps,&lt;/p&gt;

\[x_{k+1} = x_k + \Delta t\, v_\theta(x_k, t_k, s), \qquad t_k = k\,\Delta t, \quad \Delta t = 1/K, \quad k = 0, \dots, K-1,\]

&lt;p&gt;and outputs \(a = x_K\). Run with any deterministic sampler (this Euler scheme, the probability-flow ODE of a diffusion policy, DDIM with zero variance, or a one-step distilled model), the policy becomes a fixed map&lt;/p&gt;

\[a = \psi_\theta(s, w), \qquad w \sim \mathcal{N}(0, I),\]

&lt;p&gt;and all of its randomness enters through \(w\). Table 1 (click to expand) collects the notation used in the rest of the post; the decoder parameters \(\theta\) are pretrained and stay frozen, and only the proposer parameters \(\phi\) are learned.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;&lt;strong&gt;Table 1.&lt;/strong&gt; Notation.&lt;/summary&gt;

  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;Symbol&lt;/th&gt;
        &lt;th&gt;Meaning&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;\(s,\ a\)&lt;/td&gt;
        &lt;td&gt;state and action (for robot policies, often a chunk of future actions)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;\(w \in \mathbb{R}^{d}\)&lt;/td&gt;
        &lt;td&gt;noise fed to the generator; for flow policies, \(d\) equals the action dimension&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;\(v_\theta,\ K\)&lt;/td&gt;
        &lt;td&gt;velocity field of the pretrained flow, and the number of sampler steps&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;\(\psi_\theta(s, w)\)&lt;/td&gt;
        &lt;td&gt;the &lt;strong&gt;decoder&lt;/strong&gt;: the deterministic sampler that maps noise \(w\) to action \(a\)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;\(f_{\#}\mu\)&lt;/td&gt;
        &lt;td&gt;pushforward: the distribution of \(f(x)\) when \(x \sim \mu\)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;\(\pi_{\text{base}}(\cdot \mid s)\)&lt;/td&gt;
        &lt;td&gt;the pretrained policy, \(\psi_\theta(s, \cdot)_{\#}\, \mathcal{N}(0, I)\)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;\(q_\phi(w \mid s)\)&lt;/td&gt;
        &lt;td&gt;the &lt;strong&gt;noise proposer&lt;/strong&gt; (encoder), usually a state-conditioned Gaussian&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;\(\pi_\phi(\cdot \mid s)\)&lt;/td&gt;
        &lt;td&gt;the steered policy, \(\psi_\theta(s, \cdot)_{\#}\, q_\phi(\cdot \mid s)\)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;\(Q(s, a)\)&lt;/td&gt;
        &lt;td&gt;an action-value estimate (critic)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;\(\beta &amp;gt; 0\)&lt;/td&gt;
        &lt;td&gt;temperature: weight of the KL penalty that keeps \(q_\phi\) near \(\mathcal{N}(0, I)\)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;\(q^\star,\ \pi^\star\)&lt;/td&gt;
        &lt;td&gt;the optimal tilted noise distribution and policy, defined in Section 2&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;

&lt;/details&gt;

&lt;p&gt;A noise-space method keeps \(\theta\) fixed and replaces only the distribution of the input, from \(\mathcal{N}(0, I)\) to \(q_\phi(\cdot \mid s)\). The proposer can be a Gaussian with a state-dependent mean and variance, a deterministic map, a residual added to fresh noise, or even a single constant vector. It is usually smaller than the generator, though not necessarily tiny: Noise PPO uses a roughly 187M-parameter proposer. The decoder can be very large (DSRL steers \(\pi_0\), a 3.3B-parameter generalist policy) and is never updated.&lt;/p&gt;

&lt;p&gt;DSRL states the construction cleanly. Define a new MDP whose actions are noises:&lt;/p&gt;

\[P^{W}(\cdot \mid s, w) = P(\cdot \mid s, \psi_\theta(s, w)), \qquad r^{W}(s, w) = r(s, \psi_\theta(s, w)).\]

&lt;p&gt;The diffusion policy becomes part of the environment. Any RL algorithm can now run over \(w\), using only forward passes of the generator, without its weights or its intermediate denoising steps.&lt;/p&gt;

&lt;p&gt;The idea is older than diffusion policies. PLAS (Zhou et al., 2020) learned a policy in the latent space of a conditional VAE for offline RL. PARROT (Singh et al., 2021) trained a normalizing-flow behavioral prior and ran RL on its noise. It compared directly against a conditional-VAE latent space and argued that invertibility lets the agent keep full control over the final action. DSRL singles out PARROT as the precedent in control and makes the same point from the other side: diffusion models are not invertible by construction, so it is “much less clear” that steering their noise is expressive enough. In practice, it turned out to be.&lt;/p&gt;

&lt;h2 id=&quot;2-reading-it-as-a-vae&quot;&gt;2. Reading it as a VAE&lt;/h2&gt;

&lt;p&gt;Recall the evidence lower bound of an ordinary VAE (Kingma &amp;amp; Welling, 2014); a conditional VAE additionally conditions its distributions on context:&lt;/p&gt;

\[\log p(x) \;\ge\; \mathbb{E}_{q_\phi(z \mid x)}\big[\log p_\theta(x \mid z)\big] \;-\; \mathrm{KL}\big(q_\phi(z \mid x) \,\Vert\, p(z)\big).\]

&lt;p&gt;To make the connection precise, consider the following KL-regularized policy-improvement objective:&lt;/p&gt;

\[J(\phi) = \mathbb{E}_{s}\Big[\, \mathbb{E}_{w \sim q_\phi(\cdot \mid s)}\, Q\big(s, \psi_\theta(s, w)\big) \;-\; \beta\, \mathrm{KL}\big(q_\phi(\cdot \mid s) \,\Vert\, \mathcal{N}(0, I)\big) \Big].\]

&lt;p&gt;Here \(Q\) is held fixed during the proposer update, and states are sampled from a fixed training distribution. This is a local improvement objective, not by itself a complete solution to sequential RL. Table 2 lines up the two expressions term by term.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;&lt;strong&gt;Table 2.&lt;/strong&gt; VAE terms and their noise-space counterparts.&lt;/summary&gt;

  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;VAE&lt;/th&gt;
        &lt;th&gt;Noise-space RL&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;observed input \(x\)&lt;/td&gt;
        &lt;td&gt;desired optimality, with state \(s\) as context&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;encoder \(q_\phi(z \mid x)\)&lt;/td&gt;
        &lt;td&gt;noise proposer \(q_\phi(w \mid s)\)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;prior \(p(z) = \mathcal{N}(0, I)\)&lt;/td&gt;
        &lt;td&gt;the Gaussian the flow was trained from&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;decoder \(p_\theta(x \mid z)\)&lt;/td&gt;
        &lt;td&gt;frozen flow \(\psi_\theta(s, w)\)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;reconstruction \(\log p_\theta(x \mid z)\)&lt;/td&gt;
        &lt;td&gt;value \(Q(s, \psi_\theta(s, w)) / \beta\)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;KL to the prior&lt;/td&gt;
        &lt;td&gt;KL to \(\mathcal{N}(0, I)\): penalize departure from the training prior&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;decoder trained jointly&lt;/td&gt;
        &lt;td&gt;decoder pretrained by imitation, usually frozen&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;

&lt;/details&gt;

&lt;p&gt;The exact connection is a variational identity. Define \(Z(s) = \mathbb{E}_{w \sim \mathcal{N}(0,I)}[\exp(Q(s, \psi_\theta(s,w))/\beta)]\) and assume it is finite. Then, for each state,&lt;/p&gt;

\[\log Z(s) = \underbrace{\mathbb{E}_{q_\phi}[Q(s, \psi_\theta(s,w))/\beta] - \mathrm{KL}(q_\phi \Vert \mathcal{N}(0,I))}_{J(\phi;\, s)/\beta} + \mathrm{KL}(q_\phi \Vert q^\star).\]

&lt;p&gt;The last term is nonnegative, so the first two terms form a lower bound. In the control-as-inference view (Levine, 2018), this can be read as an ELBO for a desired “optimality” observation. When \(Q\) is bounded above, a state-dependent scaling makes the exponential a valid binary likelihood; the variational identity itself needs only a finite \(Z(s)\). The unrestricted best proposer is&lt;/p&gt;

\[q^\star(w \mid s) = \frac{\mathcal{N}(w; 0, I)\, \exp\big(Q(s, \psi_\theta(s, w))/\beta\big)}{Z(s)}.\]

&lt;p&gt;Writing \(J(\phi; s)\) for the term inside the outer expectation of \(J\), the identity also gives a ruler: for any proposer, \(\log Z(s) - J(\phi; s)/\beta = \mathrm{KL}(q_\phi \Vert q^\star)\) measures how far it is from the best one. Section 4 uses it.&lt;/p&gt;

&lt;p&gt;The difference from an ordinary VAE is what counts as the observation. The encoder is not asked to explain an action that was seen. It is asked to infer which noise &lt;em&gt;would have produced a good action&lt;/em&gt;. The evidence is desired success, represented here by the value estimate. This is why “VAE-style” is more accurate than calling every method a conditional VAE. A deterministic proposer, for example, has infinite KL to a continuous Gaussian; box constraints, spherical latents, and supervised inversion require their own objectives.&lt;/p&gt;

&lt;p&gt;Two facts make this reading useful rather than decorative. Eyring et al. (2025) state both for distilled text-to-image generators, and both carry over to policies without change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tilting the noise tilts the policy.&lt;/strong&gt; Pushing the noise posterior through the frozen decoder gives exactly the reward-tilted base policy:&lt;/p&gt;

\[\psi_\theta(s, \cdot)_{\#}\, q^\star(\cdot \mid s) \;=\; \pi^\star(\cdot \mid s) \;\propto\; \pi_{\text{base}}(\cdot \mid s)\, \exp\big(Q(s, \cdot)/\beta\big).\]

&lt;p&gt;The reason is that the tilt depends on \(w\) only through \(a = \psi_\theta(s, w)\).&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;Why the tilt commutes with decoding&lt;/summary&gt;

  &lt;p&gt;For a bounded test function \(f\), suppressing the fixed state \(s\),&lt;/p&gt;

\[\begin{aligned}
\mathbb{E}_{q^\star}[f(\psi_\theta(w))]
&amp;amp;= Z^{-1}\mathbb{E}_{w\sim\mathcal{N}(0,I)}
   [f(\psi_\theta(w))e^{Q(\psi_\theta(w))/\beta}] \\
&amp;amp;= Z^{-1}\mathbb{E}_{a\sim\pi_{\text{base}}}
   [f(a)e^{Q(a)/\beta}].
\end{aligned}\]

&lt;/details&gt;

&lt;p&gt;No invertibility is needed. This is the same target that KL-regularized fine-tuning of the whole flow aims for, but a small proposer can only approximate it as well as its distribution family and optimization allow. A single Gaussian, for example, need not represent a multimodal noise posterior. Figure 2 shows the target on a 2D example.&lt;/p&gt;

&lt;figure&gt;
  &lt;a href=&quot;/assets/img/posts/choose-the-noise/tilt-noise-tilts-policy.svg&quot; title=&quot;Open scalable figure&quot;&gt;&lt;img src=&quot;/assets/img/posts/choose-the-noise/tilt-noise-tilts-policy.png&quot; alt=&quot;Two rows of four panels for beta equal to infinity, 4, 1 and 0.1. Top: noise densities that concentrate in one wedge of the Gaussian as beta shrinks. Bottom: action samples that go from four equal clusters to a single cluster near the reward peak.&quot; width=&quot;1353&quot; height=&quot;759&quot; loading=&quot;lazy&quot; /&gt;&lt;/a&gt;
  &lt;figcaption&gt;&lt;strong&gt;Figure 2.&lt;/strong&gt; Tilting the noise tilts the policy (exact, no learning). The base policy is a four-cluster mixture in a 2D action space, and \(\psi\) is the exact flow-matching ODE map onto it. Each column is one value of \(\beta\). Top: the tilted noise distribution \(q^\star(w) \propto \mathcal{N}(w; 0, I)\, e^{Q(\psi(w))/\beta}\) (shading) and samples from it (dots); grey lines split the noise plane into the four regions that decode to the four clusters. Bottom: the same samples after the frozen flow, over the tilted policy \(\pi_{\text{base}}\, e^{Q/\beta}\) (shading); dashed circles are contours of \(Q\), and the star marks its peak. At \(\beta = \infty\) we recover the base policy. As \(\beta\) shrinks, probability moves to the cluster nearest the peak, but no new cluster appears.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;The noise-space KL is a conservative proxy.&lt;/strong&gt; By the data processing inequality,&lt;/p&gt;

\[\mathrm{KL}\big(\pi_\phi(\cdot \mid s) \,\Vert\, \pi_{\text{base}}(\cdot \mid s)\big) \;\le\; \mathrm{KL}\big(q_\phi(\cdot \mid s) \,\Vert\, \mathcal{N}(0, I)\big),\]

&lt;p&gt;with equality when \(\psi_\theta(s, \cdot)\) is invertible. The left side can be expensive to evaluate: a continuous normalizing flow can compute densities through divergence integration, while a generic distilled decoder need not offer a tractable density. For a Gaussian proposer \(\mathcal{N}(\mu, \mathrm{diag}\,\sigma^2)\), the right side is the familiar VAE term \(\tfrac12 \sum_j (\mu_j^2 + \sigma_j^2 - 1 - \log \sigma_j^2)\). Noise PPO (Miao et al., 2025) uses exactly this KL penalty, together with an entropy bonus. Noise Hypernetworks and LP-DS (Simsir &amp;amp; Oguz, 2026) write the steered noise as a residual \(w = \epsilon + \Delta\) and approximate the KL by \(\tfrac12\, \mathbb{E}\Vert\Delta\Vert^2\), a surrogate justified under regularity and small-Jacobian assumptions. Bounding the residual’s magnitude alone does not establish those assumptions.&lt;/p&gt;

&lt;h2 id=&quot;3-where-rl-takes-effect-carrying-value-into-noise-space&quot;&gt;3. Where RL takes effect: carrying value into noise space&lt;/h2&gt;

&lt;p&gt;The decision variable for RL is now the noise. Much of the available supervision, however, lives in the other space. An action-space critic \(Q(s, a)\) is ordinary temporal-difference learning on \((s, a, r, s&apos;)\) transitions, and offline datasets, demonstrations, and human corrections all come labeled with actions, not noises. The proposer needs a value of \(w\), or a gradient with respect to \(w\), of the composition&lt;/p&gt;

\[w \;\longmapsto\; Q\big(s, \psi_\theta(s, w)\big).\]

&lt;p&gt;This simplifies the policy interface but not necessarily the optimization: nearby noises may have very different values. So the central design question of the family is how to &lt;strong&gt;carry an action-space value back into noise space&lt;/strong&gt;. The papers suggest five routes, summarized in Figure 3. They are not disjoint categories: Route 4 is a special case of Route 3, and a method can combine inversion with a noise critic. What separates them is what each needs from the decoder: forward calls only, an inverse, or derivatives.&lt;/p&gt;

&lt;figure&gt;
  &lt;a href=&quot;/assets/img/posts/choose-the-noise/five-routes.svg&quot; title=&quot;Open scalable figure&quot;&gt;&lt;img src=&quot;/assets/img/posts/choose-the-noise/five-routes.png&quot; alt=&quot;Five rows, each with noise space on the left, the frozen decoder in the middle, and action space on the right. Route 1: a regression arrow from the action critic to a noise critic. Route 2: a corrected action inverted back through the decoder. Route 3: a gradient passing through five solver steps. Route 4: a gradient passing through one step. Route 5: returns going straight to a likelihood-ratio gradient, bypassing the decoder.&quot; width=&quot;1416&quot; height=&quot;1202&quot; loading=&quot;lazy&quot; /&gt;&lt;/a&gt;
  &lt;figcaption&gt;&lt;strong&gt;Figure 3.&lt;/strong&gt; Five routes for training the noise proposer. In each row, noise space is on the left, the frozen decoder in the middle, and action space on the right. Grey dashed arrows are forward decoding; orange arrows show what crosses back into noise space. Route 1 is drawn in its two-critic form; Route 2 uses action supervision rather than a critic; Route 5 uses returns directly. Representative methods are listed at the right of each row.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Route 1: learn a critic in noise space.&lt;/strong&gt; One option is to learn a noise-space critic directly from rollouts, as in DSRL-SAC. DSRL-NA (“noise-aliased”) instead keeps two critics. It learns \(Q^{A}(s, a)\) by temporal-difference learning in action space, then distills it into a noise-space critic by regressing \(Q^{W}(s, w)\) onto \(Q^{A}(s, \psi_\theta(s, w))\) with \(w \sim \mathcal{N}(0, I)\). The decoder is only ever run forward. Because many noises decode to similar actions, a noise that was never played can still receive an accurate value. On Robomimic Square, plain SAC in noise space (DSRL-SAC) needs about twice as many samples. On real robots, DSRL reports cases where success rose from 20% to 90% within fewer than 50 online episodes. LP-DS keeps the same two-critic design. A related forward-only idea appears in GoldenStart (Zhang et al., 2026), which picks the highest-value noise for each state by decoding candidates and scoring them with the critic, then fits a conditional VAE to these noises as a learned prior. GoldenStart is not a pure frozen-decoder method, though: its flow teacher keeps training, and the deployed policy is a distilled one-step student. &lt;em&gt;Cost:&lt;/em&gt; a second approximation. LPS argues that a distilled critic can match values well and still point its gradient in the wrong direction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Route 2: invert the flow and move the data.&lt;/strong&gt; Sometimes the signal is an action rather than a reward: a human correction, or a coarse suggestion from a vision-language model. A flow can be integrated backwards to recover the noise that would have produced that action, \(w^\star \approx \psi_\theta^{-1}(s, a^\star)\), and the corrected actions become noise-space training targets. A generic VAE decoder has no inverse, so it relies on a learned encoder for inference. An exact ODE flow is invertible under suitable regularity assumptions; a coarse numerical sampler or a distilled decoder need not be. FlowDAgger (Murray et al., 2026) regresses the proposer onto inverted corrections. UniSteer (Lu et al., 2026) stores inverted transitions \((s, \hat w, r, s&apos;)\) in both a demonstration buffer and an RL buffer, and trains a noise-space critic on them by ordinary TD learning. Flow Reversal Steering (Tang et al., 2026) maps coarse reference actions to nearby modes of a generalist policy, then distills them or uses them to bootstrap DSRL. Inversion supplies a noise that reconstructs the correction, not a sample from the reward-tilted posterior above. &lt;em&gt;Cost:&lt;/em&gt; inversion error. With the short ODE schedules of robot action heads, a naive reverse Euler step is not accurate enough, which is why FlowDAgger and UniSteer both use per-step fixed-point refinement for their flow action heads. Convergence requires conditions such as a step size small relative to the velocity field’s Lipschitz constant; it is not automatic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Route 3: backpropagate through the sampling iterations.&lt;/strong&gt; The chain rule gives the noise gradient exactly:&lt;/p&gt;

\[\nabla_w\, Q\big(s, \psi_\theta(s, w)\big) = \Big(\frac{\partial \psi_\theta}{\partial w}\Big)^{\!\top} \nabla_a Q(s, a),\]

\[\frac{\partial \psi_\theta}{\partial w} = \prod_{k=K-1}^{0} \Big(I + \Delta t\, \frac{\partial v_\theta}{\partial x}(x_k, t_k, s)\Big)\]

&lt;p&gt;for the \(K\)-step Euler sampler of Section 1, with later-step Jacobians multiplying on the left. “Exact” here means the derivative of the implemented sampler and learned critic, not of the true environment return. With a reparameterized proposer \(w = \mu_\phi(s) + \sigma_\phi(s) \odot \epsilon\), this is the VAE reparameterization trick with a frozen decoder, and no second critic is needed. D-Flow (Ben-Hamu et al., 2024) takes this route for per-sample noise optimization in image, audio, and molecule generation. &lt;em&gt;Cost:&lt;/em&gt; the gradient has to pass through every step of the solver. DSRL calls this “computationally intensive and numerically unstable”, and LPS calls it “expensive and unstable”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Route 4: make the decoder one step.&lt;/strong&gt; If \(\psi_\theta\) is a single network evaluation, the product above has a single factor, and the critic gradient reaches the noise in one backward pass. LPS (Im et al., 2026) uses a one-step MeanFlow base policy for exactly this reason, and backpropagates \(\nabla_a Q\) straight into the latent actor without a noise-space critic. It is a useful architectural neighbor rather than a strictly frozen-decoder method: its Algorithm 1 also updates the base policy by imitation during training. ReNO does the same with reward models on one-step image generators, and Noise Hypernetworks on distilled one- or few-step generators (SD-Turbo, SANA-Sprint, FLUX-Schnell). With a few steps the chain in Route 3 is short rather than trivial, which is still cheap. &lt;em&gt;Cost:&lt;/em&gt; the base policy must be one-step, which usually means it was trained or distilled for that purpose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Route 5: skip the transfer.&lt;/strong&gt; The likelihood-ratio gradient of the return term, \(\mathbb{E}\big[\nabla_\phi \log q_\phi(w \mid s)\, A(s, w)\big]\) with an advantage estimate \(A\), needs only \(\log q_\phi\), which is exact for a Gaussian proposer: no ODE divergence, no SDE conversion, no surrogate likelihood. Much of the survey’s online-RL section is about recovering a usable likelihood for flow policies; in noise space the problem does not arise. Noise PPO treats text-to-image generation as a one-step MDP whose action is the initial noise, and runs PPO with sampled rewards; KL and entropy regularizers contribute additional gradient terms. &lt;em&gt;Cost:&lt;/em&gt; the usual variance of score-function estimates.&lt;/p&gt;

&lt;h2 id=&quot;4-a-two-dimensional-experiment&quot;&gt;4. A two-dimensional experiment&lt;/h2&gt;

&lt;p&gt;To see the five routes at work, I trained the same noise proposer with each of them on a toy problem small enough to plot and to evaluate exactly. The code for this section and all figures is &lt;a href=&quot;https://github.com/Chi-Shan0707/choose-the-noise&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup.&lt;/strong&gt; Actions are points \(a \in \mathbb{R}^2\). The base policy imitates the four-cluster mixture of Figure 2: a small velocity network (an MLP) is trained once by conditional flow matching and then frozen, and the decoder \(\psi_\theta\) is its \(K = 10\)-step Euler sampler. The pushforward of \(\mathcal{N}(0, I)\) through it puts between 24.9% and 25.1% of its mass on each cluster. A state is a goal angle \(s \in [0, 2\pi)\), and the critic is known exactly: \(Q(s, a) = -\tfrac12 \Vert a - g(s) \Vert^2\), where the goal \(g(s)\) lies on the circle through the cluster centers. With \(\beta = 1\), a goal between two clusters makes \(q^\star\) bimodal. The proposer is a Gaussian \(\mathcal{N}(\mu_\phi(s), \mathrm{diag}\,\sigma_\phi(s)^2)\) whose mean and log standard deviation come from a small MLP, initialized at the prior \(\mathcal{N}(0, I)\).&lt;/p&gt;

&lt;p&gt;Because \(Q\) is given, the experiment isolates the transfer step: there is no TD learning and no exploration. The ruler from Section 2 measures the result: \(\mathrm{KL}(q_\phi \Vert q^\star) = \log Z(s) - J(\phi; s)/\beta\), estimated by Monte Carlo and averaged over 64 evenly spaced states.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How the noise moves.&lt;/strong&gt; Figure 4 follows one state during training with Route 3. The proposer starts as the prior, so the actions are the base policy. Within a few dozen updates, the noise cloud shrinks and slides into the region of noise space that decodes to the cluster nearest the goal; the actions follow it without any change to the decoder.&lt;/p&gt;

&lt;p&gt;In this state the goal lies between two clusters, so the target policy is bimodal. One Gaussian is nonetheless enough to reach both: the two clusters decode from adjacent regions of noise space, and the proposer settles across their shared boundary. &lt;strong&gt;A distribution that is bimodal in action space can be unimodal in noise space.&lt;/strong&gt; What the Gaussian cannot match is the shape of \(q^\star\), which is cut off sharply along the grey lines; a few of its samples also still decode to the two far clusters. The remaining \(\mathrm{KL}(q_\phi \Vert q^\star)\) at this state is about 0.17 nats.&lt;/p&gt;

&lt;figure&gt;
  &lt;a href=&quot;/assets/img/posts/choose-the-noise/experiment-training.svg&quot; title=&quot;Open scalable figure&quot;&gt;&lt;img src=&quot;/assets/img/posts/choose-the-noise/experiment-training.png&quot; alt=&quot;Two rows of five panels over training. Top: a Gaussian noise cloud that starts at the standard normal and moves into one wedge of noise space. Bottom: the decoded actions, which start as four clusters and concentrate on the cluster nearest the goal star.&quot; width=&quot;1367&quot; height=&quot;636&quot; loading=&quot;lazy&quot; /&gt;&lt;/a&gt;
  &lt;figcaption&gt;&lt;strong&gt;Figure 4.&lt;/strong&gt; Learning which noise to choose, for one state (goal angle 67.5°) with Route 3. Columns are snapshots during training. Top: samples from the proposer \(q_\phi(w \mid s)\) (dots) and its two-standard-deviation ellipse (orange), over the exact tilted posterior \(q^\star\) for the learned decoder (shading); grey lines separate the noise regions that decode to different clusters. Bottom: the same samples after the frozen 10-step decoder, over the tilted target policy \(\pi_{\text{base}}\, e^{Q/\beta}\) (shading, computed from the mixture the flow imitates); the star is the goal and dashed circles are contours of \(Q\). The decoder never changes; only the noise does.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Comparing the routes.&lt;/strong&gt; Each route trains the same proposer for 2,000 updates, each on 1,024 decoded noises (256 states with 4 noises each), and is run with three seeds. Routes 1, 3, 4, and 5 maximize the objective \(J\) of Section 2, using a distilled noise critic, gradients through the 10 Euler steps, gradients through a one-step decoder distilled from the 10-step sampler, and a likelihood-ratio gradient with a leave-one-out baseline. Route 2 never sees \(Q\). It receives “corrected” actions sampled from the tilted target policy, a stand-in for an expert, inverts them through the decoder by fixed-point iteration, and fits the proposer to the recovered noises by maximum likelihood. Table 3 and Figure 5 summarize the outcome.&lt;/p&gt;

&lt;figure class=&quot;table&quot;&gt;
  &lt;figcaption style=&quot;margin: 0 0 .4em&quot;&gt;&lt;strong&gt;Table 3.&lt;/strong&gt; Five routes on the 2D toy. \(\mathrm{KL}(q_\phi \Vert q^\star)\) is averaged over 64 states (mean ± standard deviation over three seeds; lower is better). Time is the median wall-clock time per update on a laptop GPU (RTX 5060), including Python overhead. Route 4 is measured against the posterior of its own one-step decoder.&lt;/figcaption&gt;

  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;Route&lt;/th&gt;
        &lt;th&gt;Needs from the decoder&lt;/th&gt;
        &lt;th&gt;\(\mathrm{KL}(q_\phi \Vert q^\star)\)&lt;/th&gt;
        &lt;th&gt;ms / update&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;1. noise critic&lt;/td&gt;
        &lt;td&gt;forward calls&lt;/td&gt;
        &lt;td&gt;0.207 ± 0.004&lt;/td&gt;
        &lt;td&gt;8.6&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2. inversion&lt;/td&gt;
        &lt;td&gt;an inverse (20 fixed-point iterations per step)&lt;/td&gt;
        &lt;td&gt;0.312 ± 0.007&lt;/td&gt;
        &lt;td&gt;60.2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;3. backprop through 10 steps&lt;/td&gt;
        &lt;td&gt;derivatives&lt;/td&gt;
        &lt;td&gt;0.211 ± 0.002&lt;/td&gt;
        &lt;td&gt;7.2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;4. one-step decoder&lt;/td&gt;
        &lt;td&gt;derivatives of a distilled one-step student&lt;/td&gt;
        &lt;td&gt;0.206 ± 0.002&lt;/td&gt;
        &lt;td&gt;2.9&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;5. likelihood ratio&lt;/td&gt;
        &lt;td&gt;forward calls&lt;/td&gt;
        &lt;td&gt;0.211 ± 0.003&lt;/td&gt;
        &lt;td&gt;5.6&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;reference: best Gaussian for each state separately&lt;/td&gt;
        &lt;td&gt;derivatives&lt;/td&gt;
        &lt;td&gt;0.198&lt;/td&gt;
        &lt;td&gt;—&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;

&lt;/figure&gt;

&lt;figure&gt;
  &lt;a href=&quot;/assets/img/posts/choose-the-noise/experiment-routes.svg&quot; title=&quot;Open scalable figure&quot;&gt;&lt;img src=&quot;/assets/img/posts/choose-the-noise/experiment-routes.png&quot; alt=&quot;Top: for each of the five routes, the final noise proposer and its decoded actions for one state. Bottom: KL to the optimal noise posterior over training for the five routes, on a log scale.&quot; width=&quot;1427&quot; height=&quot;1029&quot; loading=&quot;lazy&quot; /&gt;&lt;/a&gt;
  &lt;figcaption&gt;&lt;strong&gt;Figure 5.&lt;/strong&gt; Five routes, one proposer. (a) The final proposer of each route for the same state as Figure 4, drawn as in Figure 4 (seed 0). (b) \(\mathrm{KL}(q_\phi \Vert q^\star)\) averaged over 64 states during training; lines are means and bands span three seeds. The dashed line is the best single Gaussian fitted to each state separately.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Three things stand out.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;The four routes that maximize \(J\) end in the same place.&lt;/strong&gt; Routes 1, 3, 4, and 5 reach 0.206–0.211 nats, against 0.198 for the best single Gaussian fitted to each state separately. In this toy the remaining error comes from the Gaussian family, not from the transfer route, and amortizing over states costs little.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;They differ in how they get there.&lt;/strong&gt; Route 1 starts slowly, because its noise critic has to be learned before its gradient means anything (Figure 5b). The cost per update spans a factor of twenty: 2.9 ms through the one-step decoder, 7.2 ms through ten Euler steps, and 60 ms for inversion.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Route 2 settles higher, and not because inversion fails.&lt;/strong&gt; Fixed-point inversion reconstructs the corrected actions to a median error of about \(10^{-7}\); a single naive reverse Euler pass per step leaves a median error of 0.05, about an eighth of a cluster’s standard deviation (0.38). The difference lies in the objective. Maximum likelihood on samples from the target minimizes \(\mathrm{KL}(q^\star \Vert q_\phi)\), which favors a wider Gaussian that covers the posterior (Figure 5a), while the ruler measures \(\mathrm{KL}(q_\phi \Vert q^\star)\). Corrections teach the proposer to imitate the target, not to optimize the objective.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These numbers come from a deliberately easy setting: two dimensions, an exact critic, and a smooth decoder. They say nothing about critic error, about the variance of Route 5 in high dimensions, or about the instability that DSRL and LPS report for Route 3 with large decoders. What the toy does show is the shape of the problem: the decoder fixes which actions are reachable, the proposer only decides how much noise to send to each region, and a single Gaussian must choose between regions when the target has several.&lt;/p&gt;

&lt;h2 id=&quot;5-a-map-of-the-family&quot;&gt;5. A map of the family&lt;/h2&gt;

&lt;p&gt;Table 4 groups the methods by their main learning route. It includes related designs with changing decoders, labeled explicitly. “Prior control” distinguishes actual constraints from initialization or supervision alone.&lt;/p&gt;

&lt;details&gt;
  &lt;summary&gt;&lt;strong&gt;Table 4.&lt;/strong&gt; The family at a glance, grouped by route.&lt;/summary&gt;

  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;Route&lt;/th&gt;
        &lt;th&gt;Method&lt;/th&gt;
        &lt;th&gt;Setting&lt;/th&gt;
        &lt;th&gt;Proposer \(q_\phi(w \mid s)\)&lt;/th&gt;
        &lt;th&gt;Prior control&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;1. noise critic&lt;/td&gt;
        &lt;td&gt;PARROT (2021; preprint 2020)&lt;/td&gt;
        &lt;td&gt;robot manipulation&lt;/td&gt;
        &lt;td&gt;RL policy over the noise of an invertible normalizing flow&lt;/td&gt;
        &lt;td&gt;prior initialization; no lasting proximity guarantee&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;1. noise critic&lt;/td&gt;
        &lt;td&gt;DSRL (2025)&lt;/td&gt;
        &lt;td&gt;online and offline control; \(\pi_0\)&lt;/td&gt;
        &lt;td&gt;state-conditioned noise actor; SAC, or an action critic distilled into a noise critic&lt;/td&gt;
        &lt;td&gt;noise box \([-b, b]^d\)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;1. noise critic&lt;/td&gt;
        &lt;td&gt;LP-DS (2026)&lt;/td&gt;
        &lt;td&gt;online control; \(\pi_0\)&lt;/td&gt;
        &lt;td&gt;residual \(\epsilon + \Delta_\phi(s, \epsilon)\) with noise-aliased critics&lt;/td&gt;
        &lt;td&gt;Lagrangian trust region on \(\mathbb{E}\Vert\Delta\Vert^2\)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;1. forward scoring&lt;/td&gt;
        &lt;td&gt;GoldenStart (2026)&lt;/td&gt;
        &lt;td&gt;distilled one-step flow policies; teacher not frozen&lt;/td&gt;
        &lt;td&gt;conditional VAE fit to the highest-value noise per state&lt;/td&gt;
        &lt;td&gt;CVAE fitting; entropy control is on the action student&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2. inversion&lt;/td&gt;
        &lt;td&gt;FlowDAgger, UniSteer (2026)&lt;/td&gt;
        &lt;td&gt;human-in-the-loop VLA adaptation&lt;/td&gt;
        &lt;td&gt;noise policy regressed onto inverted corrections; UniSteer adds a noise critic&lt;/td&gt;
        &lt;td&gt;inverted targets; inversion alone does not ensure typical noise&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;2. inversion&lt;/td&gt;
        &lt;td&gt;Flow Reversal Steering (2026)&lt;/td&gt;
        &lt;td&gt;generalist policies&lt;/td&gt;
        &lt;td&gt;auxiliary noise policy trained on inverted coarse actions&lt;/td&gt;
        &lt;td&gt;coarse references guide reversal; no generic KL bound&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;3 / 4. backpropagation&lt;/td&gt;
        &lt;td&gt;ReFORM (2026)&lt;/td&gt;
        &lt;td&gt;offline RL; BC model and distilled decoder also trained&lt;/td&gt;
        &lt;td&gt;reflected flow generating bounded input noise&lt;/td&gt;
        &lt;td&gt;projected steps keep noise inside the source ball&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;4. one-step&lt;/td&gt;
        &lt;td&gt;Noise Hypernetworks (2025)&lt;/td&gt;
        &lt;td&gt;distilled text-to-image&lt;/td&gt;
        &lt;td&gt;residual on fresh noise (LoRA), reward gradient through the generator&lt;/td&gt;
        &lt;td&gt;\(\tfrac12\Vert\Delta\Vert^2\) as a KL surrogate&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;4. one-step&lt;/td&gt;
        &lt;td&gt;LPS (2026)&lt;/td&gt;
        &lt;td&gt;offline RL; real robots; base also trained by imitation&lt;/td&gt;
        &lt;td&gt;latent actor on a sphere, \(\nabla_a Q\) through a one-step MeanFlow&lt;/td&gt;
        &lt;td&gt;sphere of radius \(\sqrt{d}\)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;5. likelihood ratio&lt;/td&gt;
        &lt;td&gt;Noise PPO (2025)&lt;/td&gt;
        &lt;td&gt;text-to-image&lt;/td&gt;
        &lt;td&gt;prompt-conditioned Gaussian trained by PPO&lt;/td&gt;
        &lt;td&gt;KL to \(\mathcal{N}(0, I)\), entropy bonus&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;5. likelihood ratio&lt;/td&gt;
        &lt;td&gt;GoRL (2025)&lt;/td&gt;
        &lt;td&gt;online control&lt;/td&gt;
        &lt;td&gt;Gaussian encoder; decoder refit in alternating phases&lt;/td&gt;
        &lt;td&gt;KL to \(\mathcal{N}(0, I)\)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;search&lt;/td&gt;
        &lt;td&gt;Golden Ticket (2026)&lt;/td&gt;
        &lt;td&gt;generative robot policies&lt;/td&gt;
        &lt;td&gt;one constant noise vector found by search&lt;/td&gt;
        &lt;td&gt;—&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;

&lt;/details&gt;

&lt;p&gt;ReFORM spans Routes 3 and 4: its original objective differentiates through the BC flow, and its practical design introduces one-step BC distillation to shorten this path. Its Algorithm 1 also continues fitting the BC model. D-Flow is a per-sample example of Route 3.&lt;/p&gt;

&lt;p&gt;Three neighbors are worth knowing. PDP (Zhang et al., 2026) argues that Gaussian noise is a poorly conditioned control interface. Instead of steering it, PDP trains a literal VAE over whole demonstrations, with a geometry-alignment term, and modulates the denoiser with the resulting low-dimensional code. Condition-dependent source flow matching (Kim et al., 2026) and LAFM (Machado et al., 2026) learn the prior itself together with the flow at training time, which in VAE terms is a learned prior. D-Flow (Ben-Hamu et al., 2024) and ReNO (Eyring et al., 2024) optimize the noise separately for each sample instead of training a proposer.&lt;/p&gt;

&lt;h2 id=&quot;6-what-the-vae-view-explains&quot;&gt;6. What the VAE view explains&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The decoder fixes the map, not a safety guarantee.&lt;/strong&gt; With a frozen decoder, every steered action lies in the image of \(\psi_\theta(s, \cdot)\). For finite \(Q\) and positive \(\beta\), the ideal tilted policy has the same support as the base policy. But support is not the same as likely or reliable behavior: a Gaussian-driven invertible flow can have full support, including actions far from the demonstrations. ReFORM makes a stronger construction by bounding the source support; relating its learned model’s support to the dataset still depends on how well that model fits. A truly unreachable action cannot be recovered by steering, while a very unlikely action might be. GoRL (Zhang et al., 2025) changes the map itself by training the decoder again. Its decoder starts as an identity-like map. Training then alternates between two phases: optimizing a Gaussian encoder with a KL penalty toward \(\mathcal{N}(0, I)\) while the decoder is frozen, and refitting the decoder by flow matching on recent rollouts while the encoder is frozen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;\(\beta\) is a dial between the base policy and high-value actions.&lt;/strong&gt; For a fixed, well-behaved \(Q\), as \(\beta \to \infty\) the ideal proposer approaches the prior and the system returns to the base policy. This resembles posterior collapse in a VAE, though here returning to the base can be intentional. As \(\beta \to 0\), mass concentrates near maximizers, when they exist. Multiple equally good actions—or multiple noises for one action—can remain; a single point mass is not inevitable. LP-DS reports that prior-replacing steering can lose modes, and uses a residual trust region whose multiplier plays a role similar to \(\beta\), for its surrogate penalty. Golden Ticket (Patil et al., 2026) imposes a different restriction: one noise vector shared across states. It is not the general low-temperature limit of a state-conditioned proposer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Holes in the latent space.&lt;/strong&gt; A VAE can decode poorly in regions its training rarely visits. A Gaussian-driven flow can have the same problem: most training draws come from typical regions of the Gaussian. The family uses several ways to discourage atypical queries, with different strengths. DSRL bounds each noise coordinate in \([-b,b]\) and reports that \(b\) between 1 and 3 works well online. A box bounds coordinates; it does not by itself enforce the Gaussian’s typical radius. LPS trains both its base policy and its latent actor on the sphere of radius \(\sqrt{d}\), where high-dimensional Gaussian mass concentrates, to prevent what it calls “norm explosion”; strictly, its prior is uniform on that sphere rather than \(\mathcal{N}(0, I)\). LP-DS bounds the squared norm of its residual, its stand-in for the KL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aliasing makes some noise changes redundant.&lt;/strong&gt; Many noises can decode to similar actions. This is related to latent ambiguity, but distinct from the statistical non-identifiability of a VAE’s latent coordinates. DSRL-NA turns this weakness into data sharing across noises. The same fact explains why the noise KL is only an upper bound: when the decoder is genuinely many-to-one, part of the KL budget can be spent on redistributing noise among identical outputs. For an invertible flow the KLs remain equal, even if different noises produce very similar actions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amortization has a gap.&lt;/strong&gt; Optimizing noise separately for each sample (D-Flow, ReNO) and training a proposer that predicts it (Noise Hypernetworks, whose subtitle is “Amortizing Test-Time Compute”) are the policy-side versions of per-datapoint variational inference and an amortized encoder. The cost of amortization has a name in the VAE literature, the amortization gap (Cremer et al., 2018). Noise Hypernetworks report recovering a substantial portion of the gains of explicit test-time optimization at a fraction of its cost, which illustrates the quality–compute tradeoff. That comparison is not, by itself, a measurement of the formal variational amortization gap.&lt;/p&gt;

&lt;h2 id=&quot;7-open-questions&quot;&gt;7. Open questions&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;When is a policy steerable?&lt;/strong&gt; DSRL notes that the base policy must be “steerable” for the method to work and studies when this holds empirically, but does not give a formal definition. Nothing in the construction guarantees useful steering in advance. It helps to separate three questions: can the decoder produce a good action, does the allowed proposer put enough probability on its preimages, and can the learning signal find them? Invertibility addresses only the first.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;How does the number of sampling steps matter?&lt;/strong&gt; Noise PPO finds the largest gains at few inference steps; the benefit shrinks, but does not disappear, as the number of steps grows. Several robot papers rely on one-step or few-step decoders for different reasons: cheap Jacobians for LPS, low latency for robot control. Few steps are not free, however: FlowDAgger finds that coarse steps make naive inversion inaccurate.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;When should the decoder be trained?&lt;/strong&gt; Freezing the decoder preserves the learned map and can improve sample efficiency; training it, as in GoRL, can change which useful behaviors are easy to represent. Where a pretrained policy should sit between the two is not settled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;A practical reading rule.&lt;/strong&gt; If the decoder is available only through forward calls, start by considering a noise critic or a likelihood-ratio update. If corrections are available, inversion may turn them into direct supervision. If gradients are available and the sampler is short, direct backpropagation avoids critic distillation. Then check the paper’s actual prior constraint and whether the decoder stays frozen; the shared diagram does not settle either question.&lt;/p&gt;

&lt;p&gt;The survey’s second axis asks where the RL signal enters a flow-matching method. This family adds one more answer to that question: &lt;strong&gt;the RL signal can enter through the input-noise distribution.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Nahim, N. Z., Khan, F. N., &amp;amp; Ju, P. (2026). &lt;a href=&quot;https://arxiv.org/abs/2610.16275&quot;&gt;A Survey of Flow Matching in Reinforcement Learning&lt;/a&gt;. &lt;em&gt;TMLR&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Wagenmaker, A., Nakamoto, M., Zhang, Y., et al. (2025). &lt;a href=&quot;https://arxiv.org/abs/2506.15799&quot;&gt;Steering Your Diffusion Policy with Latent Space Reinforcement Learning&lt;/a&gt;. (DSRL)&lt;/li&gt;
  &lt;li&gt;Singh, A., Liu, H., Zhou, G., Yu, A., Rhinehart, N., &amp;amp; Levine, S. (2021). &lt;a href=&quot;https://arxiv.org/abs/2011.10024&quot;&gt;PARROT: Data-Driven Behavioral Priors for Reinforcement Learning&lt;/a&gt;. &lt;em&gt;ICLR&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Zhou, W., Bajracharya, S., &amp;amp; Held, D. (2020). &lt;a href=&quot;https://arxiv.org/abs/2011.07213&quot;&gt;PLAS: Latent Action Space for Offline Reinforcement Learning&lt;/a&gt;. &lt;em&gt;CoRL&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Miao, Y., Loh, W., Poupart, P., &amp;amp; Kothawade, S. (2025). &lt;a href=&quot;https://arxiv.org/abs/2506.12036&quot;&gt;A Minimalist Method for Fine-tuning Text-to-Image Diffusion Models&lt;/a&gt;. (Noise PPO)&lt;/li&gt;
  &lt;li&gt;Eyring, L., Karthik, S., Dosovitskiy, A., Ruiz, N., &amp;amp; Akata, Z. (2025). &lt;a href=&quot;https://arxiv.org/abs/2508.09968&quot;&gt;Noise Hypernetworks: Amortizing Test-Time Compute in Diffusion Models&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Eyring, L., Karthik, S., Roth, K., Dosovitskiy, A., &amp;amp; Akata, Z. (2024). &lt;a href=&quot;https://arxiv.org/abs/2406.04312&quot;&gt;ReNO: Enhancing One-step Text-to-Image Models through Reward-based Noise Optimization&lt;/a&gt;. &lt;em&gt;NeurIPS&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Ben-Hamu, H., Puny, O., et al. (2024). &lt;a href=&quot;https://arxiv.org/abs/2402.14017&quot;&gt;D-Flow: Differentiating through Flows for Controlled Generation&lt;/a&gt;. &lt;em&gt;ICML&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Zhang, C., Wan, Z., Chen, F., Yu, X., Tsang, I., &amp;amp; An, B. (2025). &lt;a href=&quot;https://arxiv.org/abs/2512.02581v1&quot;&gt;GoRL: An Algorithm-Agnostic Framework for Online Reinforcement Learning with Generative Policies&lt;/a&gt;. The current arXiv version is titled &lt;em&gt;Training Diffusion Policies via Prior-Mapping Co-Evolution&lt;/em&gt;; this post follows v1.&lt;/li&gt;
  &lt;li&gt;Zhang, H., Sun, Y., &amp;amp; Xiong, H. (2026). &lt;a href=&quot;https://arxiv.org/abs/2603.14245&quot;&gt;GoldenStart: Q-Guided Priors and Entropy Control for Distilling Flow Policies&lt;/a&gt;. &lt;em&gt;ICLR&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Simsir, H., &amp;amp; Oguz, O. S. (2026). &lt;a href=&quot;https://arxiv.org/abs/2606.01151&quot;&gt;Lagrangian Perturbation Diffusion Steering: Latent Reinforcement Learning for Generative Policies&lt;/a&gt;. &lt;em&gt;ICML&lt;/em&gt;. (LP-DS)&lt;/li&gt;
  &lt;li&gt;Im, H., Kolobov, A., Fu, J., &amp;amp; Lee, Y. (2026). &lt;a href=&quot;https://arxiv.org/abs/2603.05296&quot;&gt;Latent Policy Steering through One-Step Flow Policies&lt;/a&gt;. &lt;em&gt;RSS&lt;/em&gt;. (LPS)&lt;/li&gt;
  &lt;li&gt;Zhang, S., So, O., Ahmad, H. M. S., Yu, E. Y., Cleaveland, M., Black, M., &amp;amp; Fan, C. (2026). &lt;a href=&quot;https://arxiv.org/abs/2602.05051&quot;&gt;ReFORM: Reflected Flows for On-Support Offline RL via Noise Manipulation&lt;/a&gt;. &lt;em&gt;ICLR&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Murray, M., Chen, D., Bagaria, S., et al. (2026). &lt;a href=&quot;https://arxiv.org/abs/2607.08877&quot;&gt;FlowDAgger: Human-in-the-Loop Adaptation of Generative Robot Policies in Latent Space&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Lu, J., Qin, X., et al. (2026). &lt;a href=&quot;https://arxiv.org/abs/2605.10821&quot;&gt;UniSteer: Unified Noise Steering for Efficient Human-Guided VLA Adaptation&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Tang, A., Chen, W., Wagenmaker, A., Finn, C., &amp;amp; Levine, S. (2026). &lt;a href=&quot;https://arxiv.org/abs/2606.13675&quot;&gt;Improving Robotic Generalist Policies via Flow Reversal Steering&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Patil, O., Biza, O., Weng, T., et al. (2026). &lt;a href=&quot;https://arxiv.org/abs/2603.15757&quot;&gt;You’ve Got a Golden Ticket: Improving Generative Robot Policies With A Single Noise Vector&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Zhang, R., Fu, H., Jia, M., Konidaris, G., Du, Y., &amp;amp; da Silva, B. C. (2026). &lt;a href=&quot;https://arxiv.org/abs/2606.00336&quot;&gt;From Noise to Control: Parameterized Diffusion Policies&lt;/a&gt;. &lt;em&gt;ICML&lt;/em&gt;. (PDP)&lt;/li&gt;
  &lt;li&gt;Kim, J., Park, J., Jeon, S., &amp;amp; Kim, S. (2026). &lt;a href=&quot;https://arxiv.org/abs/2602.05951&quot;&gt;Better Source, Better Flow: Learning Condition-Dependent Source Distribution for Flow Matching&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Machado, B., Chapin, A., Dellandréa, E., &amp;amp; Chen, L. (2026). &lt;a href=&quot;https://arxiv.org/abs/2606.23420&quot;&gt;Flowing With Purpose: Latent Action Guided Flow Matching Policies for Robotic Manipulation&lt;/a&gt;. (LAFM)&lt;/li&gt;
  &lt;li&gt;Kingma, D. P., &amp;amp; Welling, M. (2014). &lt;a href=&quot;https://arxiv.org/abs/1312.6114&quot;&gt;Auto-Encoding Variational Bayes&lt;/a&gt;. &lt;em&gt;ICLR&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Levine, S. (2018). &lt;a href=&quot;https://arxiv.org/abs/1805.00909&quot;&gt;Reinforcement Learning and Control as Probabilistic Inference: Tutorial and Review&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Cremer, C., Li, X., &amp;amp; Duvenaud, D. (2018). &lt;a href=&quot;https://proceedings.mlr.press/v80/cremer18a.html&quot;&gt;Inference Suboptimality in Variational Autoencoders&lt;/a&gt;. &lt;em&gt;ICML&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;details&gt;
&lt;summary&gt;Cite this post&lt;/summary&gt;
&lt;p&gt;If you find this post useful in your work, you can cite it as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Chi, Yuhan. “Choose the Noise, Keep the Flow.” October 18, 2026. &lt;a href=&quot;https://yuhanchi.github.io/writing/choose-the-noise/&quot;&gt;https://yuhanchi.github.io/writing/choose-the-noise/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Or use the following BibTeX entry:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bibtex&quot;&gt;@misc{chi2026choosethenoise,
  author = {Chi, Yuhan},
  title = {{Choose the Noise, Keep the Flow}},
  year = {2026},
  month = oct,
  day = {18},
  howpublished = {Blog post},
  url = {https://yuhanchi.github.io/writing/choose-the-noise/}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This citation refers to the blog’s explanation and synthesis. Please cite the original papers above for their methods and results.&lt;/p&gt;
&lt;/details&gt;
</content>
  </entry>
  <entry>
    <title>What Is Luck?</title>
    <link href="https://yuhanchi.github.io/writing/what-is-luck/"/>
    <id>https://yuhanchi.github.io/writing/what-is-luck/</id>
    <updated>2026-10-15T00:00:00+08:00</updated><summary>A moment after a lecture made me rethink luck and the effort behind an opportunity.</summary>
    <content type="html">&lt;p&gt;What is luck? It is really a good question. With the wind, even pigs can fly.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;I always admire some friends’ luck, or destiny. Many golden opportunities fall into their laps! They meet visionary people by chance, or receive unexpected invitations to study or intern.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;I think I at least work hard, but lack some luck. However, today’s lecture changed my view. A professor gave a lecture. Although it was a little difficult and I got lost in the second half, a senior of mine mentioned a paper, “DiffusionNFT,” and was curious about its relationship to the method in the lecture. “Fortunately,” I had read that paper! She had other things to attend to and had to leave early, so she couldn’t continue the discussion. I got an “opportunity” to follow up on her question and explain the paper’s algorithm in more detail on her behalf, carrying the discussion forward (though I could only explain the algorithm and couldn’t fully follow the professor’s analysis of it). The professor was interested in that topic.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Did I gain any rewards from that process? Nothing, exxcept acknowledgement—acknowledgement of the knowledge and understanding I had accumulated over time. If I hadn’t read enough papers, I couldn’t have known what they were referring to or explained the algorithm intuitively to the professor.Similarly, my friend is a bold, almost reckless person and never hesitates to connect with anyone. His character is like that, so he does it naturally.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;This motivates me to keep working on &lt;a href=&quot;/writing/knowing-is-not-enough/&quot;&gt;deep thinking and accumulation&lt;/a&gt;. This time, the chance encounter was a positive one, but I believe the same applies to setbacks: the knowledge and understanding I accumulate can help me turn those into opportunities too.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;When enough effort has been devoted, odds become opportunities. Luck, in turn, is part of your calibre.&lt;br /&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Knowing Is Not Enough</title>
    <link href="https://yuhanchi.github.io/writing/knowing-is-not-enough/"/>
    <id>https://yuhanchi.github.io/writing/knowing-is-not-enough/</id>
    <updated>2026-10-11T00:00:00+08:00</updated><summary>Why reading many papers stopped making me better, and the questions I now ask while reading.</summary>
    <content type="html">&lt;p&gt;Today, a senior asked me, “You say you read many papers, but how do you know whether a paper has taken effect after you read it?” I was tongue-tied.&lt;/p&gt;

&lt;p&gt;I have run into this kind of problem a lot lately. In fact, I have felt stuck in a kind of stagnation since this summer. I seemed to have done and experienced many things, but in the end I had only “known” them. This discouraged me a lot: my meta-abilities and my understanding had barely improved, despite my apparent diligence.&lt;/p&gt;

&lt;p&gt;That is a serious problem. After all, I devoted my time, my attention and my energy. Ideally, whether an experiment or a study succeeds or fails, I should come away with some understanding from it.&lt;/p&gt;

&lt;p&gt;There is a common temptation. New techniques, trends and other fancy things are attractive, and there is some bar even to “knowing” them. So we spend a certain amount of time and energy getting to know them, and then we are easily satisfied. That is terrible.&lt;/p&gt;

&lt;p&gt;Reading papers has a similar trap: we are awed by novel ideas and forget to think critically. The figures and graphs may be impressive, but a series of questions should still be asked:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;What is the baseline or benchmark?&lt;/strong&gt; The authors claim strong results, but strong compared with what? If I have read the related papers, I should know the common baselines. Is a common baseline missing? Does the benchmark truly match the problem?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Why this method?&lt;/strong&gt; If they use PPO, was that forced by a constraint (e.g. a continuous action space rules out plain Q-learning), or were there real alternatives? Did they justify the choice? If they say an abandoned method gave unstable training losses, did they actually find and explain the reason?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Where does the gain come from?&lt;/strong&gt; How do the authors explain their edge over other methods? The ablation experiments may prove something. But does the reasoning part, such as arguments about the manifold or about multiple modes, really convince me?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;What obstacles did I run into while reading?&lt;/strong&gt; If I ran into some, I deal with them. But what if I have no questions at all? There are only two possibilities: either I truly understand it, or I am trusting my instinct, which says everything is fine. Then I always need to ask one more question: is my instinct trustworthy? Many pitfalls hide beneath instinct.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;What am I reading this paper for?&lt;/strong&gt; Is it to push back the frontier of my knowledge, or just to learn a technique more deeply?&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach is not only for reading papers; I believe I can apply it to many other things. As a freshman, I might have been proud of “having dabbled in many areas.” Now that I am a sophomore, things should change. Harder, deeper and more critical thinking should become part of my daily study.&lt;/p&gt;

&lt;p&gt;Besides, I need to output. Output forces me to understand and then regenerate. When I explain something again, I automatically rethink the problem. Chats, seminars, talks: I will try them all.&lt;/p&gt;

&lt;p&gt;So here is the answer I did not have that day: a paper has taken effect if I can rebuild its argument without looking, say where it would fail, and use it in my own work. If all I can say is “I’ve read it,” then I only &lt;em&gt;know&lt;/em&gt; it.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Proofs as Observations</title>
    <link href="https://yuhanchi.github.io/writing/proofs-as-observations/"/>
    <id>https://yuhanchi.github.io/writing/proofs-as-observations/</id>
    <updated>2026-09-30T00:00:00+08:00</updated><summary>A question about AI and mathematics: could the proofs we obtain become the starting point for what we understand?</summary>
    <content type="html">&lt;h2 id=&quot;what-happens-after-an-ai-produces-a-proof&quot;&gt;What happens after an AI produces a proof?&lt;/h2&gt;

&lt;p&gt;Much of the discussion concerns whether the proof is correct, elegant, or genuinely useful. I have been wondering about a further possibility:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mathematics could remain deductive in justification while becoming more empirical in how we discover structures and form theories.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Discussions about AI proofs often turn to elegance and understanding. A machine might produce a correct argument that is long, awkward, or difficult to learn from. That seems like a limitation. But perhaps such a proof could also be a beginning.&lt;/p&gt;

&lt;h3 id=&quot;proofs-as-observations&quot;&gt;Proofs as observations&lt;/h3&gt;

&lt;p&gt;In the past, we could only observe small examples or special cases that humans can handle by hand. With AI, observation can be extended to a far larger scale. The intermediate objects, reductions, and constructions of complex counterexamples become material to study. They are the phenomena of mathematical principles, and observations that can scale up.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-mermaid&quot;&gt;flowchart TD
    A[&quot;Mathematician: ask related questions&amp;lt;br/&amp;gt;and propose conjectures from partial knowledge&quot;]
    B[&quot;AI assistant: seek proofs or counterexamples&amp;lt;br/&amp;gt;Verify results before treating them as observations&quot;]
    C[&quot;Mathematician: synthesize observations&amp;lt;br/&amp;gt;Find shared constructions and limits of validity&quot;]
    D[&quot;Distill concepts and prove general theorems&amp;lt;br/&amp;gt;Deepen understanding of the mathematical object&quot;]
    A --&amp;gt; B --&amp;gt; C --&amp;gt; D
    C --&amp;gt;|Design further mathematical experiments| A
    D --&amp;gt;|Ask new questions| A
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Like observations that helped physicists develop thermodynamics, verified proofs and counterexamples can guide mathematicians toward underlying structures. Summarizing these observations and testing further conjectures creates a cycle of discovery; advances in AI can make this cycle easier to repeat at scale.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Terence Tao’s &lt;a href=&quot;https://terrytao.wordpress.com/2024/10/12/the-equational-theories-project-a-brief-tour/&quot;&gt;brief tour of the Equational Theories Project&lt;/a&gt; gives a concrete example of exploring a large family of mathematical questions with machine assistance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;verification-and-understanding-are-different-achievements&quot;&gt;Verification and understanding are different achievements&lt;/h3&gt;

&lt;p&gt;Verification settles truth, but understanding still lives in the mind rather than the compiler. Mathematicians have long turned opaque arguments into understanding by reworking them, and a collection of machine-generated proofs could sometimes invite the same process. An awkward proof may contain a useful idea that has not yet been expressed clearly.&lt;/p&gt;

&lt;h3 id=&quot;some-concerns&quot;&gt;Some concerns&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;What about failures?&lt;/strong&gt; Failures are ambiguous. Failing to find a proof or counterexample may reflect the model’s limitations or the nature of the conjecture itself. We need to distinguish the two.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Will lock-in take place and we stop delving into foundations?&lt;/strong&gt; I believe mathematicians can notice repeated friction in AI’s output. That is where we should revisit our foundations.&lt;/li&gt;
&lt;/ul&gt;

&lt;details&gt;
&lt;summary&gt;Cite this post&lt;/summary&gt;
&lt;p&gt;If you find this post useful in your work, you can cite it as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Chi, Yuhan. “Proofs as Observations.” September 30, 2026. &lt;a href=&quot;https://yuhanchi.github.io/writing/proofs-as-observations/&quot;&gt;https://yuhanchi.github.io/writing/proofs-as-observations/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Or use the following BibTeX entry:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bibtex&quot;&gt;@misc{chi2026proofs,
  author = {Chi, Yuhan},
  title = {{Proofs as Observations}},
  year = {2026},
  month = sep,
  howpublished = {Blog post},
  url = {https://yuhanchi.github.io/writing/proofs-as-observations/}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
</content>
  </entry>
  <entry>
    <title>Choice and Alignment</title>
    <link href="https://yuhanchi.github.io/writing/choice-and-alignment/"/>
    <id>https://yuhanchi.github.io/writing/choice-and-alignment/</id>
    <updated>2026-08-14T00:00:00+08:00</updated><summary>How social choice theory and Arrow&apos;s theorem help explain trade-offs in AI alignment.</summary>
    <content type="html">&lt;p&gt;Is it possible to please everyone?&lt;/p&gt;

&lt;p&gt;In a society, we all have our own preferences, yet we often need to reach a collective decision or ranking. This is the basic question of social choice
theory. It also resembles a central problem in AI alignment: a system may need to act on behalf of many people whose values are neither identical nor easy to compare.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Arrow’s framework makes this question precise.&lt;/p&gt;

&lt;h2 id=&quot;alternatives-and-individuals&quot;&gt;Alternatives and individuals&lt;/h2&gt;

&lt;p&gt;Let&lt;/p&gt;

\[X = \{x_1, x_2, \ldots, x_m\}\]

&lt;p&gt;be a finite set of &lt;strong&gt;alternatives&lt;/strong&gt;. These may be candidates in an election,
public policies, or possible actions of an AI system. Let&lt;/p&gt;

\[N = \{1, 2, \ldots, n\}\]

&lt;p&gt;be the set of &lt;strong&gt;individuals&lt;/strong&gt; in the society.&lt;/p&gt;

&lt;p&gt;Each individual $i \in N$ has a preference relation $\succeq_i$ over $X$. The
statement $x \succeq_i y$ means that individual $i$ considers $x$ at least as
good as $y$. We normally require this relation to be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;complete&lt;/strong&gt;: for any $x,y \in X$, either $x \succeq_i y$ or
$y \succeq_i x$ (or both); and&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;transitive&lt;/strong&gt;: if $x \succeq_i y$ and $y \succeq_i z$, then
$x \succeq_i z$.&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- ($x,y,z \in X $)&lt;br&gt; --&gt;

&lt;p&gt;A complete and transitive preference relation is called a &lt;strong&gt;weak order&lt;/strong&gt;. Its
strict part is written $\succ_i$: $x \succ_i y$ means that $i$ strictly prefers
$x$ to $y$. Indifference is written $x \sim_i y$.&lt;/p&gt;

&lt;p&gt;Let $\mathcal{R}(X)$ denote the set of all weak orders over $X$.&lt;/p&gt;

&lt;h2 id=&quot;preference-profiles-and-society&quot;&gt;Preference profiles and society&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;preference profile&lt;/strong&gt; records the preferences of everyone in the society:&lt;/p&gt;

\[R = (\succeq_1, \succeq_2, \ldots, \succeq_n)
  \in \mathcal{R}(X)^N.\]

&lt;p&gt;The set $\mathcal{R}(X)^N$ is called the &lt;strong&gt;preference-profile space&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Thus, a preference profile is not itself a social ranking. It is the complete
input to an aggregation rule: one preference relation for each individual. In
this formal model, $N$ is the &lt;strong&gt;society&lt;/strong&gt;, while $R$ is the society’s preference
profile over the set of alternatives $X$.&lt;/p&gt;

&lt;p&gt;For example, suppose three people rank three alternatives as follows:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Individual&lt;/th&gt;
      &lt;th&gt;Ranking&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;$x \succ_1 y \succ_1 z$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;$y \succ_2 z \succ_2 x$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;3&lt;/td&gt;
      &lt;td&gt;$z \succ_3 x \succ_3 y$&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Pairwise majority voting gives $x \succ y$, $y \succ z$, and $z \succ x$.
Although every individual ranking is transitive, the majority relation is
cyclic. This is the &lt;strong&gt;Condorcet paradox&lt;/strong&gt;, and it shows why aggregation is not
simply a matter of counting pairwise votes.&lt;/p&gt;

&lt;h2 id=&quot;from-a-profile-to-a-social-ranking&quot;&gt;From a profile to a social ranking&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;social welfare function&lt;/strong&gt; is a rule&lt;/p&gt;

\[F: \mathcal{R}(X)^N \longrightarrow \mathcal{R}(X)\]

&lt;p&gt;that maps every preference profile $R$ to a complete and transitive &lt;strong&gt;social
preference relation&lt;/strong&gt;, or &lt;strong&gt;social ranking&lt;/strong&gt;, $F(R)$. It does not merely select
a winner; it ranks all alternatives for society as a whole.&lt;/p&gt;

&lt;p&gt;This distinction matters. A &lt;strong&gt;social choice function&lt;/strong&gt; instead maps a profile
to one chosen alternative (or a set of chosen alternatives). Arrow’s theorem is
usually stated for social welfare functions.&lt;/p&gt;

&lt;h2 id=&quot;arrows-requirements&quot;&gt;Arrow’s requirements&lt;/h2&gt;

&lt;p&gt;As we learn in geometry, we should build from the most basic elements.&lt;/p&gt;

&lt;p&gt;After these primitive definitions, what kinds of axioms come to mind?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Should it satisfy &lt;strong&gt;universality&lt;/strong&gt;? It seems natural that every preference
profile should be mapped to a social ranking.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Should it follow &lt;strong&gt;unanimity&lt;/strong&gt;? If everyone strictly prefers $x$ to
$y$—that is, $x \succ_i y$ for every $i \in N$—then shouldn’t the social
ranking also have $x \succ y$?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;What about &lt;strong&gt;independence of irrelevant alternatives&lt;/strong&gt;? Should the relative
ranking of $x$ and $y$ depend only on how people compare $x$ with $y$,
regardless of how good or bad another alternative $z$ is?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Should it satisfy &lt;strong&gt;monotonicity&lt;/strong&gt;? Suppose the current social ranking has
$x \succ y$. If an individual $k$ changes their preference from
$x \prec_k y$ to $x \succ_k y$, shouldn’t the social ranking still have
$x \succ y$?
This idea also relies on condition 3: reversing the relation between $x$ and
$y$ may affect how they compare with other alternatives, but those changes
should not affect the collective comparison between $x$ and $y$, right?&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;More importantly, just as in Euclidean geometry, we want as few axioms as
possible. It turns out that condition 4 can be derived from the first three.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lemma (Monotonicity).&lt;/strong&gt; Suppose a social welfare function satisfies
universality, unanimity, and IIA. If its social ranking has $x \succ y$ under a
preference profile $R$, and one individual changes their preference from
$x \prec_k y$ to $x \succ_k y$, then the social ranking under the new profile
$R’$ still has $x \succ y$.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Proof.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Suppose that, under a preference profile $R$, the individuals in a group $G$
prefer $x$ to $y$, while everyone outside $G$ prefers $y$ to $x$. Nevertheless,
the resulting social ranking has $x \succ y$.&lt;/p&gt;

&lt;p&gt;Now choose an individual $k \notin G$ and change only their comparison of $x$
and $y$, from $x \prec_k y$ to $x \succ_k y$. Call the resulting preference
profile $R’$. We want to show that its social ranking still has $x \succ y$.&lt;/p&gt;

&lt;p&gt;Introduce a third alternative $z$ and construct two auxiliary profiles,
$R_1$ and $R_2$. The relevant preferences in all four profiles are:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Individuals&lt;/th&gt;
      &lt;th&gt;$R$&lt;/th&gt;
      &lt;th&gt;$R_1$&lt;/th&gt;
      &lt;th&gt;$R_2$&lt;/th&gt;
      &lt;th&gt;$R’$&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;$i \in G$&lt;/td&gt;
      &lt;td&gt;$x \succ_i y$&lt;/td&gt;
      &lt;td&gt;$x \succ_i y \succ_i z$&lt;/td&gt;
      &lt;td&gt;$x \succ_i z \succ_i y$&lt;/td&gt;
      &lt;td&gt;$x \succ_i y$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;$k$&lt;/td&gt;
      &lt;td&gt;$y \succ_k x$&lt;/td&gt;
      &lt;td&gt;$y \succ_k x \succ_k z$&lt;/td&gt;
      &lt;td&gt;$x \succ_k z \succ_k y$&lt;/td&gt;
      &lt;td&gt;$x \succ_k y$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;$j \notin G \cup {k}$&lt;/td&gt;
      &lt;td&gt;$y \succ_j x$&lt;/td&gt;
      &lt;td&gt;$y \succ_j z \succ_j x$&lt;/td&gt;
      &lt;td&gt;$z \succ_j y \succ_j x$&lt;/td&gt;
      &lt;td&gt;$y \succ_j x$&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Can you see how to prove it? Think boldly!&lt;/p&gt;

&lt;p&gt;First consider $R_1$. Every individual compares $x$ with $y$ exactly as they
do under $R$. By IIA, the social comparison is unchanged, so $x \succ y$ under
$R_1$. Moreover, everyone prefers $y$ to $z$. By unanimity, the social ranking
has $y \succ z$. Transitivity then gives $x \succ z$.&lt;/p&gt;

&lt;p&gt;Next consider $R_2$. Every individual compares $x$ with $z$ exactly as they do
under $R_1$. By IIA, we retain $x \succ z$. Everyone also prefers $z$ to $y$,
so unanimity gives $z \succ y$. By transitivity, $x \succ y$ under $R_2$.&lt;/p&gt;

&lt;p&gt;Finally, every individual compares $x$ with $y$ in the same way under $R_2$ and
$R’$. Applying IIA once more gives $x \succ y$ under $R’$. Thus, moving one
individual’s preference in favor of $x$ cannot cause $x$ to fall below $y$ in
the social ranking. This is exactly monotonicity.&lt;/p&gt;

\[\square\]

&lt;h2 id=&quot;when-social-choice-becomes-alignment&quot;&gt;When social choice becomes alignment&lt;/h2&gt;

&lt;p&gt;A instinctive idea is whether we can apply this theory to LLM, especially &lt;em&gt;alignment&lt;/em&gt;.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;We can easily formulate a very simple one-to-one corresponding between AI alignment and Social choice theory.&lt;br /&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;AI alignment&lt;/th&gt;
      &lt;th&gt;Social choice theory&lt;/th&gt;
      &lt;th&gt;Notation&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Model responses, actions, or trajectories&lt;/td&gt;
      &lt;td&gt;Alternatives&lt;/td&gt;
      &lt;td&gt;$x \in X$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Annotators, users, or stakeholders&lt;/td&gt;
      &lt;td&gt;Individuals&lt;/td&gt;
      &lt;td&gt;$i \in N$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;One person’s comparison of model behaviors&lt;/td&gt;
      &lt;td&gt;Individual preference relation&lt;/td&gt;
      &lt;td&gt;$\succeq_i$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;All human feedback&lt;/td&gt;
      &lt;td&gt;Preference profile&lt;/td&gt;
      &lt;td&gt;$R=(\succeq_1,\ldots,\succeq_n)$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Feedback-aggregation procedure&lt;/td&gt;
      &lt;td&gt;Social welfare function&lt;/td&gt;
      &lt;td&gt;$F$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Collective ordering learned from feedback&lt;/td&gt;
      &lt;td&gt;Social ranking&lt;/td&gt;
      &lt;td&gt;$F(R)$&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The crucial step is still the same: many individual rankings are compressed into one collective target. &lt;br /&gt;
If alignment is meant to incorporate everyone’s
ordering, then the model must somehow turn a profile of diverse human preferences into one coherent ranking of its possible behaviors.&lt;/p&gt;

&lt;p&gt;And now an uncomfortable concern arises. Will the model’s values be dominated
by a small group of people who hold the power to define them? More sharply,
could there be a single &lt;em&gt;dominator&lt;/em&gt;—one voice whose preferences always become
the model’s preferences?&lt;/p&gt;

&lt;p&gt;Actually, Arrow gives this concern a precise name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Definition (Dictator).&lt;/strong&gt; An individual $d \in N$ is a dictator if, for every
preference profile and every pair $x,y \in X$, $x \succ_d y$ always implies
$x \succ y$ in the social ranking, regardless of what everyone else prefers.&lt;/p&gt;

&lt;p&gt;Surely we would also want &lt;strong&gt;non-dictatorship&lt;/strong&gt;: no such individual should
exist. Yet this final wish conflicts with the apparently natural requirements
we already imposed.&lt;/p&gt;

&lt;h2 id=&quot;a-dictator-always-exists&quot;&gt;A dictator always exists&lt;/h2&gt;

&lt;p&gt;Let $G \subseteq N$ and let $x,y \in X$.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Definition (Weakly decisive set).&lt;/strong&gt; The set $G$ is weakly decisive (or
&lt;em&gt;almost decisive&lt;/em&gt;) for $x$ over $y$ if&lt;/p&gt;

\[\left.
\begin{aligned}
x &amp;amp;\succ_i y &amp;amp;&amp;amp; \text{for every } i\in G,\\
y &amp;amp;\succ_j x &amp;amp;&amp;amp; \text{for every } j\notin G
\end{aligned}
\right\}
\quad\Longrightarrow\quad
x\succ y.\]

&lt;p&gt;Thus, $G$ wins even when everyone outside $G$ takes the opposite side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Definition (Strongly decisive set).&lt;/strong&gt; The set $G$ is strongly decisive for
$x$ over $y$ if&lt;/p&gt;

\[x\succ_i y \text{ for every } i\in G
\quad\Longrightarrow\quad
x\succ y,\]

&lt;p&gt;regardless of the preferences outside $G$. A strongly decisive set is usually
called simply a &lt;strong&gt;decisive set&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The monotonicity lemma immediately connects the two definitions:&lt;/p&gt;

\[\text{weakly decisive for }(x,y)
\quad\Longrightarrow\quad
\text{strongly decisive for }(x,y).\]

&lt;p&gt;IIA first removes all comparisons unrelated to $x$ and $y$. Starting from the
worst case, in which every outsider opposes $G$, monotonicity then tells us that
moving any outsider toward $x$ cannot reverse $x\succ y$.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lemma (Field expansion).&lt;/strong&gt; If $G$ is decisive for one ordered pair, then it
is decisive for every ordered pair.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Proof.&lt;/em&gt; Suppose $G$ is decisive for $x$ over $y$. Introduce $z$ and construct&lt;/p&gt;

\[\begin{array}{c|cc}
 &amp;amp; G &amp;amp; N\setminus G \\ \hline
P_1 &amp;amp; x\succ y\succ z &amp;amp; y\succ z\succ x
\end{array}\]

&lt;p&gt;Then&lt;/p&gt;

\[\begin{aligned}
x&amp;amp;\succ y,\\
y&amp;amp;\succ z,\\
\therefore\quad x&amp;amp;\succ z.
\end{aligned}\]

&lt;p&gt;The first relation follows from decisiveness, the second from unanimity, and
the third from transitivity. Exactly $G$ supports $x$ over $z$; by IIA, the
same social comparison holds in every profile with this pairwise pattern.
Thus $G$ is weakly—and hence strongly—decisive for $x$ over $z$.&lt;/p&gt;

&lt;p&gt;Now construct&lt;/p&gt;

\[\begin{array}{c|cc}
 &amp;amp; G &amp;amp; N\setminus G \\ \hline
P_2 &amp;amp; z\succ x\succ y &amp;amp; y\succ z\succ x
\end{array}\]

&lt;p&gt;This time,&lt;/p&gt;

\[\begin{aligned}
z&amp;amp;\succ x,\\
x&amp;amp;\succ y,\\
\therefore\quad z&amp;amp;\succ y.
\end{aligned}\]

&lt;p&gt;Exactly $G$ supports $z$ over $y$, so IIA and monotonicity make $G$ decisive
for this pair as well. Repeating these two extensions reaches every ordered
pair. $\square$&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Theorem (Arrow).&lt;/strong&gt; If there are at least three alternatives, every social
welfare function satisfying universality, unanimity, and IIA has a dictator.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Proof.&lt;/em&gt; By unanimity, $N$ is decisive. Choose a decisive set $G$ of minimum
size. Suppose $|G|&amp;gt;1$ and split it into two nonempty sets:&lt;/p&gt;

\[G=G_1\mathbin{\dot\cup}G_2,
\qquad
H=N\setminus G.\]

&lt;p&gt;By universality, the following profile is admissible:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Individuals&lt;/th&gt;
      &lt;th&gt;Preference&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;$G_1$&lt;/td&gt;
      &lt;td&gt;$x \succ y \succ z$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;$G_2$&lt;/td&gt;
      &lt;td&gt;$y \succ z \succ x$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;$H$&lt;/td&gt;
      &lt;td&gt;$z \succ x \succ y$&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Every member of $G$ prefers $y$ to $z$, while everyone in $H$ prefers $z$ to
$y$. Since $G$ is decisive,&lt;/p&gt;

\[y\succ z.\]

&lt;p&gt;By completeness, either&lt;/p&gt;

\[x\succ z
\qquad\text{or}\qquad
z\succeq x.\]

&lt;p&gt;&lt;strong&gt;Case 1:&lt;/strong&gt; $x\succ z$. Exactly the members of $G_1$ prefer $x$ to $z$.
By IIA, $G_1$ is weakly decisive for $(x,z)$, hence strongly decisive for every
pair. But&lt;/p&gt;

\[\varnothing\neq G_1\subsetneq G,\]

&lt;p&gt;contradicting the minimality of $G$.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 2:&lt;/strong&gt; $z\succeq x$. From transitivity,&lt;/p&gt;

\[\begin{aligned}
y&amp;amp;\succ z,\\
z&amp;amp;\succeq x,\\
\therefore\quad y&amp;amp;\succ x.
\end{aligned}\]

&lt;p&gt;Exactly the members of $G_2$ prefer $y$ to $x$. Thus $G_2$ is weakly decisive
for $(y,x)$ by IIA, hence strongly decisive for every pair. Again,&lt;/p&gt;

\[\varnothing\neq G_2\subsetneq G,\]

&lt;p&gt;contradicting minimality.&lt;/p&gt;

&lt;p&gt;Therefore $G$ cannot contain more than one individual. Hence&lt;/p&gt;

\[G=\{d\}\]

&lt;p&gt;for some $d\in N$. Since $G$ is decisive for every ordered pair, $d$ is a
dictator.&lt;/p&gt;

\[\square\]

&lt;p&gt;Therefore universality, unanimity, IIA, and non-dictatorship cannot all hold at
once.&lt;/p&gt;

&lt;h2 id=&quot;back-to-real-alignment&quot;&gt;Back to real alignment&lt;/h2&gt;

&lt;p&gt;Before drawing any conclusion about deployed systems, it is worth being precise
about what the theorem is.&lt;/p&gt;

&lt;p&gt;Arrow’s theorem is a &lt;strong&gt;conditional&lt;/strong&gt;. It says:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;if&lt;/em&gt; a rule accepts every profile,&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;if&lt;/em&gt; its input is ordinal and interpersonally non-comparable,&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;if&lt;/em&gt; it obeys IIA, and&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;if&lt;/em&gt; it returns one complete transitive ranking over at least
three alternatives, 
&lt;br /&gt; $\rightarrow$ &lt;em&gt;then&lt;/em&gt; it has a dictator.&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But actually, every real alignment method escapes the conclusion, because every one of them violates a hypothesis. So the interesting question is never “does this system have a dictator?” It is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Which hypothesis is the system paying to avoid one, and what is the bill?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Three answers follow, and then one that says the bill cannot be avoided by
refusing to aggregate at all.&lt;/p&gt;

&lt;h3 id=&quot;what-rlhf-gives-up-independence&quot;&gt;What RLHF gives up: independence&lt;/h3&gt;

&lt;p&gt;The standard reward model is Bradley–Terry:&lt;/p&gt;

\[\Pr(y \succ y&apos;) = \sigma\big(r(y) - r(y&apos;)\big),
\qquad
\sigma(t) = \frac{1}{1 + e^{-t}}.\]

&lt;p&gt;Here $r$ is a single scalar reward fitted by maximum likelihood to comparisons
pooled across annotators. Two of Arrow’s assumptions fail at once. The reward
is cardinal rather than merely ordinal, and annotator identity is usually
discarded. The rule therefore never sees a profile
$R=(\succeq_1,\ldots,\succeq_n)$, only an unlabeled pool of comparisons.&lt;/p&gt;

&lt;p&gt;Cardinality is the classical way around Arrow’s theorem: once interpersonal
comparison is allowed, utilitarian-style rules become available. In this case,
we can also identify the aggregation rule more precisely.&lt;/p&gt;

&lt;p&gt;Recall the Borda count. With $m$ alternatives, a candidate receives a point for
each alternative ranked below it, and those points are summed across voters.
Siththaranjan, Laidlaw, and Hadfield-Menell show that preference learning
implicitly implements this rule when disagreement comes from &lt;strong&gt;hidden
context&lt;/strong&gt;, such as annotator identity, values, or labeling criteria.&lt;/p&gt;

&lt;p&gt;Once identity is discarded, each comparison is averaged over the context that
produced it. Counting wins across voters becomes the probability of winning
against a random opponent:&lt;/p&gt;

\[\mathrm{BC}(y) = \Pr_{y&apos;\sim\rho}(y\succ y&apos;),\]

&lt;p&gt;where $\rho$ is the distribution of training comparisons. Thus the aggregation
performed by RLHF is not unspecified: under these assumptions, it behaves like
the Borda rule. This is a consequence of how the data are pooled, not an
explicit design choice.&lt;/p&gt;

&lt;p&gt;Two of Borda’s known defects transfer directly.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;IIA fails operationally.&lt;/strong&gt; Suppose&lt;/p&gt;

\[\Pr(y_1\succ y_2)=0.6,\qquad \Pr(y_1\succ y_3)=0.4,\qquad \Pr(y_2\succ y_3)=0.7.\]

    &lt;table&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt; &lt;/th&gt;
          &lt;th&gt;Pair weights&lt;/th&gt;
          &lt;th&gt;$\mathrm{BC}(y_1)$&lt;/th&gt;
          &lt;th&gt;$\mathrm{BC}(y_2)$&lt;/th&gt;
          &lt;th&gt;Winner&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Uniform&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;$(y_1 y_2)=\tfrac13,\;(y_1 y_3)=\tfrac13,\;(y_2 y_3)=\tfrac13$&lt;/td&gt;
          &lt;td&gt;$0.50$&lt;/td&gt;
          &lt;td&gt;$\mathbf{0.55}$&lt;/td&gt;
          &lt;td&gt;$y_2$&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;Oversample $y_1 y_2$&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;$(y_1 y_2)=\tfrac{9}{10},\;(y_1 y_3)=\tfrac{1}{20},\;(y_2 y_3)=\tfrac{1}{20}$&lt;/td&gt;
          &lt;td&gt;$\mathbf{0.59}$&lt;/td&gt;
          &lt;td&gt;$0.42$&lt;/td&gt;
          &lt;td&gt;$y_1$&lt;/td&gt;
        &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;

    &lt;p&gt;$\Pr(y_1\succ y_2)=0.6$ in both rows. Only $y_3$’s sampling frequency changed; the winner flipped.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;The rule is manipulable.&lt;/strong&gt; Borda rewards strategic ranking. The same paper
argues that annotators may therefore benefit from misreporting their
preferences to shift the learned model, with possible downstream effects on
jailbreak robustness.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;what-constitutional-ai-gives-up-universality&quot;&gt;What Constitutional AI gives up: universality&lt;/h3&gt;

&lt;p&gt;Constitutional AI begins with a fixed set of principles rather than aggregating
an unrestricted set of preferences. In Arrow’s language, this restricts the
domain: $F$ is defined not on all of $\mathcal{R}(X)^N$, but on a subset
$\mathcal{D}\subsetneq\mathcal{R}(X)^N$. Profiles that conflict with the
constitution are not reconciled within the rule; they are treated as
inadmissible.&lt;/p&gt;

&lt;p&gt;Restricting the domain is sufficient to avoid Arrow’s conclusion. Black’s
theorem gives a standard example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Definition (Single-peaked).&lt;/strong&gt; Preferences are single-peaked with respect to
a common ordering of $X$ if each individual has an ideal point, and
satisfaction falls monotonically when moving away from it in either direction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Theorem (Black, 1948).&lt;/strong&gt; If every individual’s preference is single-peaked
with respect to one common ordering, pairwise majority rule yields a transitive
social ranking topped by the median voter’s ideal point.&lt;/p&gt;

&lt;p&gt;Under these conditions, majority rule has neither a cycle nor a dictator. The
result depends on a substantive restriction: a common axis must be specified,
and preferences must be single-peaked along it. The median voter’s ideal point
then determines the top-ranked alternative.&lt;/p&gt;

&lt;p&gt;Writing a constitution is analogous to choosing that axis. It does not remove
the aggregation problem; it moves the problem up one level, from deciding
which response is best to deciding which principles should govern responses.&lt;/p&gt;

&lt;p&gt;The question can recur: who decides how opinions about principles are combined?
This regress is not fatal; an institution can choose a stopping point and
justify it. But the stopping point remains a choice rather than a neutral
consequence of the theory.&lt;/p&gt;

&lt;h3 id=&quot;personalization-and-minimal-liberalism&quot;&gt;Personalization and minimal liberalism&lt;/h3&gt;

&lt;p&gt;A natural response is to give each user a separate policy. If no collective
ranking is required, perhaps dictatorship can be avoided.&lt;/p&gt;

&lt;p&gt;Sen’s theorem shows why this move has limits. It concerns rights rather than
rankings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Definition (Minimal liberalism).&lt;/strong&gt; A rule satisfies minimal liberalism if there exist $i \neq j$ and pairs ${x,y}, {z,w} \subseteq X$ such that $i$ is decisive over ${x,y}$, and $j$ is decisive over ${z,w}$.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Theorem (Sen, 1970).&lt;/strong&gt; No rule on the unrestricted domain satisfies both weak Pareto and minimal liberalism while always returning an acyclic social
preference.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Proof.&lt;/em&gt;&lt;/p&gt;

\[a: \text{model answers user 1}, \quad b: \text{model answers user 2}, \quad c: \text{refuses both}\]

&lt;p&gt;User 1’s sphere: ${a,c}$. User 2’s sphere: ${b,c}$.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt; &lt;/th&gt;
      &lt;th&gt;Ranking&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;$c \succ_1 a \succ_1 b$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;$a \succ_2 b \succ_2 c$&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

\[c \succ a \ (\text{sphere}_1), \qquad b \succ c \ (\text{sphere}_2), \qquad a \succ b \ (\text{Pareto})\]

\[\Rightarrow a \succ b \succ c \succ a. \qquad \square\]

&lt;p&gt;Personalization is a form of minimal liberalism: allowing user $i$ to set their
own policy grants them decisiveness over alternatives that differ only in
$i$’s affairs. The cycle requires &lt;strong&gt;external preferences&lt;/strong&gt;, meaning that people
care about choices in others’ spheres as well as their own. Without such
preferences, Pareto cannot produce the final edge of the cycle. In practice,
however, disputes over model policy often include external preferences.
Excluding them would itself be a value judgment.&lt;/p&gt;

&lt;h3 id=&quot;randomization-and-strategyproofness&quot;&gt;Randomization and strategyproofness&lt;/h3&gt;

&lt;p&gt;A decision scheme maps profiles to distributions over $X$: $d: \mathcal{R}(X)^N \to \Delta(X)$.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Definition.&lt;/strong&gt; Strategyproof: truthful reporting is always weakly optimal. Ex post Pareto optimal: never assigns positive probability to a unanimously
dominated alternative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Theorem (Gibbard, 1977).&lt;/strong&gt; With $\geq 3$ alternatives, any strategyproof,
ex post Pareto-optimal scheme is a probability mixture of dictatorships: fix
weights $(w_1,\ldots,w_n)$, draw a person, and implement that person’s top
choice.&lt;/p&gt;

&lt;p&gt;If probabilities are determined by a score, such as a Borda count or weighted
average, misreporting can shift both the score and the resulting odds. Under
random dictatorship, the weights are fixed before anyone reports. A person
cannot change their chance of being selected, and truthful reporting is
optimal once they are selected.&lt;/p&gt;

&lt;p&gt;The mechanism must still specify who enters the lottery and with what weight.
Using a smoother aggregation rule requires giving up strategyproofness and
accepting incentives to misreport.&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Arrow’s hypothesis&lt;/th&gt;
      &lt;th&gt;Given up by&lt;/th&gt;
      &lt;th&gt;What replaces it&lt;/th&gt;
      &lt;th&gt;Trade-off&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Universality&lt;/td&gt;
      &lt;td&gt;Constitutional AI, hard refusals&lt;/td&gt;
      &lt;td&gt;Restricted domain; Black-style possibility&lt;/td&gt;
      &lt;td&gt;The constitution must specify both principles and a common axis&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Ordinal, non-comparable input&lt;/td&gt;
      &lt;td&gt;Bradley–Terry reward models&lt;/td&gt;
      &lt;td&gt;Cardinal aggregation — in fact Borda count&lt;/td&gt;
      &lt;td&gt;IIA violations and incentives for strategic annotation&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;One transitive social ranking&lt;/td&gt;
      &lt;td&gt;Stochastic policies&lt;/td&gt;
      &lt;td&gt;Decision schemes&lt;/td&gt;
      &lt;td&gt;Strategyproofness and efficiency jointly permit only random dictatorship&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;One ranking for everyone&lt;/td&gt;
      &lt;td&gt;Personalization&lt;/td&gt;
      &lt;td&gt;Per-user policies&lt;/td&gt;
      &lt;td&gt;External preferences can conflict with individual decisiveness&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Every column on the right represents a choice about whose preferences count,
how they are compared, and which decisions they may govern. None of these
choices is forced by the mathematics, and none is neutral.&lt;/p&gt;

&lt;p&gt;There is no neutral aggregation rule under these requirements. In practice,
the rule’s assumptions and trade-offs should be explicit, revisable, and open
to scrutiny by the people whose preferences it aggregates.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;No rule can satisfy every preference under all conditions. What remains
possible is to state the trade-offs clearly and make the resulting decisions
accountable.&lt;/p&gt;

&lt;details&gt;
&lt;summary&gt;Cite this post&lt;/summary&gt;
&lt;p&gt;If you find this post useful in your work, you can cite it as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Chi, Yuhan. “Choice and Alignment.” August 14, 2026. &lt;a href=&quot;https://yuhanchi.github.io/writing/choice-and-alignment/&quot;&gt;https://yuhanchi.github.io/writing/choice-and-alignment/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Or use the following BibTeX entry:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bibtex&quot;&gt;@misc{chi2026choice,
  author = {Chi, Yuhan},
  title = {{Choice and Alignment}},
  year = {2026},
  month = aug,
  howpublished = {Blog post},
  url = {https://yuhanchi.github.io/writing/choice-and-alignment/}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
</content>
  </entry>
  <entry>
    <title>My Visit to Professor Ziad Obermeyer at UC Berkeley</title>
    <link href="https://yuhanchi.github.io/writing/visit-prof-obermeyer/"/>
    <id>https://yuhanchi.github.io/writing/visit-prof-obermeyer/</id>
    <updated>2026-07-15T00:00:00+08:00</updated><summary>Takeaways from meeting Professor Obermeyer at UC Berkeley School of Public Health — on applied math, interpretability, and mathematical models in healthcare.</summary>
    <content type="html">&lt;h2 id=&quot;meeting-with-professor-ziad-obermeyer-school-of-public-health&quot;&gt;Meeting with Professor Ziad Obermeyer (School of Public Health)&lt;/h2&gt;

&lt;h3 id=&quot;takeaways&quot;&gt;Takeaways&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Applied Mathematics?&lt;/strong&gt; &lt;br /&gt;
Cannot be the top in one field? Try to be in the top 5% in several fields!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;In serious scenarios, like medical systems, how much do we value interpretability?&lt;/strong&gt; &lt;br /&gt;
Very much. Interpretability in this area means that we want our models to perform well on data they haven’t seen before. Besides, we need to know if it really has a sense of “science”. For example, if I edit the symptom a little, what kind of change will happen in the output, and is the change aligned with the biology?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Why do we still need mathematical models? “The bitter lesson” has said: the data and compute will definitely outperform engineered architecture.&lt;/strong&gt; &lt;br /&gt;
We need them. First, “Garbage in, garbage out”. We need mathematical models to make some data more “high-quality”. Secondly, sometimes we cannot directly investigate the things we want. Hence, we should use mathematical models to find proxies.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  <entry>
    <title>Floating Point Notes in Computers</title>
    <link href="https://yuhanchi.github.io/writing/floating-point-notes/"/>
    <id>https://yuhanchi.github.io/writing/floating-point-notes/</id>
    <updated>2026-07-11T00:00:00+08:00</updated><summary>Notes on how computers represent floating-point numbers and why rounding errors are unavoidable.</summary>
    <content type="html">&lt;p&gt;Let’s build the concept of floating-point numbers in computers from first principles.&lt;/p&gt;

&lt;!-- We will follow a logical progression: from the physical limitations of computers, to the mathematical decisions, and finally to the engineering trade-offs that shaped the IEEE 754 standard, ultimately examining how modern CPUs execute common operations. --&gt;

&lt;h2 id=&quot;1-the-core-conflict-the-finite-cannot-represent-the-infinite&quot;&gt;1. The Core Conflict: The Finite Cannot Represent the Infinite&lt;/h2&gt;

&lt;p&gt;The real number line is perfectly continuous and stretches to infinity. However, computers use fixed-size memory registers (e.g., 32 bits or 64 bits). A 32-bit sequence can only ever represent \(2^{32}\) distinct states.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First Principle:&lt;/strong&gt; You cannot map an infinite, continuous space into a finite, discrete space without losing information. We must accept that computer mathematics will inherently involve &lt;strong&gt;approximations and rounding errors&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;2-binary-and-the-need-for-exponents&quot;&gt;2. Binary and the Need for Exponents&lt;/h2&gt;

&lt;p&gt;Computers operate in binary. Just as we use base-10 decimals, we can use binary fractions (e.g., \(1.01_2 = 1.25_{10}\)).&lt;/p&gt;

&lt;p&gt;If we used a fixed-point system, we couldn’t represent both cosmic scales (\(10^{20}\)) and quantum scales (\(10^{-10}\)) simultaneously. To cover both within just 32 bits, we borrow from scientific notation: \(a \times 10^b\). In binary, this becomes &lt;strong&gt;\(F \times 2^E\)&lt;/strong&gt;. The radix point “floats” depending on the exponent \(E\).&lt;/p&gt;

&lt;h2 id=&quot;3-floating-point-memory-layout-bit-distribution&quot;&gt;3. Floating-Point Memory Layout (Bit Distribution)&lt;/h2&gt;

&lt;p&gt;In the IEEE 754 standard, a floating-point number is stored in three parts: &lt;strong&gt;Sign (S)&lt;/strong&gt;, &lt;strong&gt;Exponent (E)&lt;/strong&gt;, and &lt;strong&gt;Fraction/Mantissa (F)&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Single Precision (float)&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; sign bit + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8&lt;/code&gt; exponent bits + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;23&lt;/code&gt; fraction bits = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;32&lt;/code&gt; bits&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Double Precision (double)&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; sign bit + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;11&lt;/code&gt; exponent bits + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;52&lt;/code&gt; fraction bits = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;64&lt;/code&gt; bits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Single Precision (32-bit) Memory Layout Diagram:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; 31  30           23  22                                      0
 +--+---------------+-----------------------------------------+
 | S|    Exponent   |                Fraction                 |
 +--+---------------+-----------------------------------------+
 1-bit   8-bit                         23-bit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Double Precision (64-bit) Memory Layout Diagram:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; 63  62                     52  51                            0
 +--+-------------------------+-------------------------------+
 | S|        Exponent         |           Fraction            |
 +--+-------------------------+-------------------------------+
 1-bit        11-bit                         52-bit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;4-engineering-trade-offs-implicit-bit-gradual-underflow-and-biased-exponent&quot;&gt;4. Engineering Trade-offs: Implicit Bit, Gradual Underflow, and Biased Exponent&lt;/h2&gt;

&lt;p&gt;When designing the standard, engineers made several major trade-offs to optimize for efficiency, speed, and mathematical continuity:&lt;/p&gt;

&lt;h3 id=&quot;trade-off-1-the-implicit-leading-bit-efficiency&quot;&gt;Trade-off 1: The Implicit Leading Bit (Efficiency)&lt;/h3&gt;

&lt;p&gt;In binary scientific notation, a normalized number always starts with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; (e.g., \(1.011_2 \times 2^3\)). Since the digit before the radix point is &lt;em&gt;always&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;, we don’t store it; we simply assume its presence. This provides &lt;strong&gt;one free bit of precision&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BUT&lt;/strong&gt;, there is a problem with the implicit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;. If every number starts with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.xxx&lt;/code&gt;, how do we represent numbers very close to 0?&lt;/p&gt;

&lt;p&gt;If the smallest exponent is \(-126\), the smallest &lt;em&gt;normalized&lt;/em&gt; positive number is \(1.0 \times 2^{-126}\). Below this, the value would abruptly jump straight to 0. This huge gap breaks the mathematical property that \(x - y = 0\) if and only if \(x = y\).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution: Denormalization (Gradual Underflow)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To fix this, the standard introduces a rule: if the Exponent field is all 0s, the implicit leading bit changes from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;These are called &lt;strong&gt;Denormalized (or Subnormal) numbers&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Denormalized numbers do not have higher precision. They actually have &lt;strong&gt;lower precision&lt;/strong&gt;, but they &lt;strong&gt;can represent numbers much closer to 0&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;As the value gets smaller, the number of leading zeros increases, and the significant bits drop from 24 down to 1. This &lt;strong&gt;gradual underflow&lt;/strong&gt; bridges the gap to 0 and prevents abrupt jumps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;trade-off-2-biased-exponent-fast-comparison&quot;&gt;Trade-off 2: Biased Exponent (Fast Comparison)&lt;/h3&gt;

&lt;p&gt;To rapidly compare two floating-point numbers, we want to feed their raw 32-bit patterns directly into standard &lt;strong&gt;integer comparison circuits&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If we used two’s complement for negative exponents, a negative exponent (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;11111111&lt;/code&gt;) would appear as a massive unsigned integer, breaking our fast integer comparison trick.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; We use a &lt;strong&gt;bias (offset)&lt;/strong&gt;. By adding a constant (e.g., 127 for single precision) to the actual exponent, all stored exponents become strictly positive. This preserves the integer sorting order!&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Single precision: \(\text{Stored } E = \text{True exponent} + 127\)&lt;/li&gt;
  &lt;li&gt;To decode: \(\text{True exponent} = \text{Stored } E - 127\)&lt;/li&gt;
  &lt;li&gt;Double precision: bias is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1023&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;5-read-the-bits-directly-extreme-values-in-32-bit-single-precision&quot;&gt;5. Read the Bits Directly: Extreme Values in 32-bit Single Precision&lt;/h2&gt;

&lt;p&gt;This is the place to stop talking in the abstract and read real &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; patterns. Single precision rule recap:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Layout: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;S&lt;/code&gt; (1 bit) | &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E&lt;/code&gt; (8 bits) | &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;F&lt;/code&gt; (23 bits), Bias = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;127&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E != 00000000&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E != 11111111&lt;/code&gt;: normalized, value = \((-1)^S \times 1.F_2 \times 2^{E_{unsigned}-127}\).&lt;/li&gt;
  &lt;li&gt;If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E == 00000000&lt;/code&gt;: denormalized / zero, value = \((-1)^S \times 0.F_2 \times 2^{-126}\). Note the exponent is fixed at \(-126\) here, not \(0-127=-127\).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overview of the six extremes:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;#&lt;/th&gt;
      &lt;th&gt;Name&lt;/th&gt;
      &lt;th&gt;32-bit pattern &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;S EEEEEEEE F...&lt;/code&gt;&lt;/th&gt;
      &lt;th&gt;Hex&lt;/th&gt;
      &lt;th&gt;Approx. value&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;
      &lt;td&gt;Largest finite positive&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 11111110 11111111111111111111111&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x7F7FFFFF&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;\(\approx +3.40 \times 10^{38}\)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;B&lt;/td&gt;
      &lt;td&gt;Smallest positive normalized&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 00000001 00000000000000000000000&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00800000&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;\(\approx +1.18 \times 10^{-38}\)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;C&lt;/td&gt;
      &lt;td&gt;Smallest positive denormalized&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 00000000 00000000000000000000001&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00000001&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;\(\approx +1.40 \times 10^{-45}\)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;D&lt;/td&gt;
      &lt;td&gt;Most negative (largest magnitude)&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1 11111110 11111111111111111111111&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xFF7FFFFF&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;\(\approx -3.40 \times 10^{38}\)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;E&lt;/td&gt;
      &lt;td&gt;Negative closest to zero, normalized&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1 00000001 00000000000000000000000&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x80800000&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;\(\approx -1.18 \times 10^{-38}\)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;F&lt;/td&gt;
      &lt;td&gt;Negative closest to zero, denormalized&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1 00000000 00000000000000000000001&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x80000001&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;\(\approx -1.40 \times 10^{-45}\)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;div class=&quot;fp-example&quot;&gt;

  &lt;p&gt;&lt;strong&gt;Case A — Largest finite positive: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 11111110 11111111111111111111111&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

  &lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;S = 0  (+)
E = 11111110
F = 11111111111111111111111  (23 ones)
Hex = 0x7F7FFFFF
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;ul&gt;
    &lt;li&gt;Exponent bits to unsigned: \(11111110_2 = 128+64+32+16+8+4+2+0 = 254_{10}\).&lt;/li&gt;
    &lt;li&gt;Minus bias: \(E_{true} = 254 - 127 = +127\).&lt;/li&gt;
    &lt;li&gt;Mantissa: \(1.F_2 = 1.111\dots111_2 = 2 - 2^{-23} \approx 1.99999988\).&lt;/li&gt;
    &lt;li&gt;Value: \((2-2^{-23}) \times 2^{127} = 2^{128} - 2^{104} \approx 3.4028235 \times 10^{38}\).&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;Why not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E = 11111111&lt;/code&gt;? That pattern is reserved for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Inf&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NaN&lt;/code&gt;, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;11111110&lt;/code&gt; is the largest finite exponent.&lt;/p&gt;

&lt;/div&gt;

&lt;div class=&quot;fp-example&quot;&gt;

  &lt;p&gt;&lt;strong&gt;Case B — Smallest positive normalized: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 00000001 00000000000000000000000&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

  &lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;S = 0  (+)
E = 00000001
F = 00000000000000000000000  (23 zeros)
Hex = 0x00800000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;ul&gt;
    &lt;li&gt;Exponent bits to unsigned: \(00000001_2 = 1_{10}\).&lt;/li&gt;
    &lt;li&gt;Minus bias: \(E_{true} = 1 - 127 = -126\).&lt;/li&gt;
    &lt;li&gt;Mantissa: \(1.000\dots000_2 = 1.0\).&lt;/li&gt;
    &lt;li&gt;Value: \(1.0 \times 2^{-126} \approx 1.17549435 \times 10^{-38}\).&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;Anything smaller in magnitude cannot stay normalized; it must become denormalized.&lt;/p&gt;

&lt;/div&gt;

&lt;div class=&quot;fp-example&quot;&gt;

  &lt;p&gt;&lt;strong&gt;Case C — Smallest positive denormalized: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 00000000 00000000000000000000001&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

  &lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;S = 0  (+)
E = 00000000  (special: denormalized)
F = 00000000000000000000001  (only LSB = 1)
Hex = 0x00000001
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;ul&gt;
    &lt;li&gt;Exponent field is all zeros, so the rule changes: leading bit is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.&lt;/code&gt;, true exponent is fixed at \(-126\) (do &lt;strong&gt;not&lt;/strong&gt; compute \(0-127=-127\)).&lt;/li&gt;
    &lt;li&gt;Mantissa: \(0.F_2 = 0.000\dots001_2 = 2^{-23}\).&lt;/li&gt;
    &lt;li&gt;Value: \(2^{-23} \times 2^{-126} = 2^{-149} \approx 1.40129846 \times 10^{-45}\).&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;This is the closest positive number to zero. One step smaller is exactly &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+0&lt;/code&gt;.&lt;/p&gt;

&lt;/div&gt;

&lt;div class=&quot;fp-example&quot;&gt;

  &lt;p&gt;&lt;strong&gt;Case D — Most negative (mirror of Case A): &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1 11111110 11111111111111111111111&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

  &lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;S = 1  (-)
E = 11111110
F = 11111111111111111111111
Hex = 0xFF7FFFFF
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;ul&gt;
    &lt;li&gt;Exponent: \(11111110_2 = 254_{10}\), \(254-127 = +127\), identical to Case A.&lt;/li&gt;
    &lt;li&gt;Value: \(-(2-2^{-23}) \times 2^{127} \approx -3.4028235 \times 10^{38}\).&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;Only the sign bit flips; exponent and fraction decoding are unchanged.&lt;/p&gt;

&lt;/div&gt;

&lt;div class=&quot;fp-example&quot;&gt;

  &lt;p&gt;&lt;strong&gt;Case E — Negative closest to zero, normalized: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1 00000001 00000000000000000000000&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

  &lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;S = 1  (-)
E = 00000001
F = 00000000000000000000000
Hex = 0x80800000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;ul&gt;
    &lt;li&gt;Exponent: \(00000001_2 = 1_{10}\), \(1-127 = -126\).&lt;/li&gt;
    &lt;li&gt;Value: \(-1.0 \times 2^{-126} \approx -1.17549435 \times 10^{-38}\).&lt;/li&gt;
  &lt;/ul&gt;

&lt;/div&gt;

&lt;div class=&quot;fp-example&quot;&gt;

  &lt;p&gt;&lt;strong&gt;Case F — Negative closest to zero, denormalized: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1 00000000 00000000000000000000001&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

  &lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;S = 1  (-)
E = 00000000  (special: denormalized)
F = 00000000000000000000001
Hex = 0x80000001
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;ul&gt;
    &lt;li&gt;Same denormalized rule: \(0.F_2 \times 2^{-126} = 2^{-23} \times 2^{-126} = 2^{-149}\).&lt;/li&gt;
    &lt;li&gt;Value: \(\approx -1.40129846 \times 10^{-45}\).&lt;/li&gt;
  &lt;/ul&gt;

&lt;/div&gt;

&lt;p&gt;Reference for intuition: the largest denormalized number &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 00000000 11111111111111111111111&lt;/code&gt; is \((1-2^{-23}) \times 2^{-126} \approx 1.17549421 \times 10^{-38}\), just one step below the smallest normalized number in Case B. That is gradual underflow in action.&lt;/p&gt;

&lt;h2 id=&quot;6-special-numbers-0-inf-nan&quot;&gt;6. Special Numbers: 0, Inf, NaN&lt;/h2&gt;

&lt;p&gt;Because our system is finite, operations can overflow or yield mathematically undefined results. To preserve our fast integer sorting trick, where should infinity live? At the very top (the largest possible exponent).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Exponent = All 1s&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;If &lt;strong&gt;Fraction == 0&lt;/strong&gt;: &lt;strong&gt;Infinity&lt;/strong&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+Inf&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-Inf&lt;/code&gt;).&lt;/li&gt;
      &lt;li&gt;If &lt;strong&gt;Fraction != 0&lt;/strong&gt;: &lt;strong&gt;NaN&lt;/strong&gt; (Not a Number, e.g., for \(\sqrt{-1}\)).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Exponent = All 0s&lt;/strong&gt;: Reserved for &lt;strong&gt;Zero&lt;/strong&gt; (if the fraction is 0) and &lt;strong&gt;Subnormals&lt;/strong&gt; (if the fraction is non-zero, see Cases C/F above).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;7-key-examples-to-test-your-understanding&quot;&gt;7. Key Examples to Test Your Understanding&lt;/h2&gt;

&lt;div class=&quot;fp-example&quot;&gt;

  &lt;p&gt;&lt;strong&gt;Example 1: What is the smallest single-precision number strictly greater than 2?&lt;/strong&gt;&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;To find this, we examine how \(2.0\) is represented.&lt;/li&gt;
    &lt;li&gt;\(2.0 = 1.0 \times 2^1\).&lt;/li&gt;
    &lt;li&gt;In Single Precision: Sign = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;, Exponent = \(1 + 127 = 128\), Fraction = \(000\dots000\) (23 zeros).&lt;/li&gt;
    &lt;li&gt;The next representable number simply increments the fraction by the smallest possible amount (setting the least significant bit, LSB, to 1).&lt;/li&gt;
    &lt;li&gt;The Fraction becomes \(000\dots001\).&lt;/li&gt;
    &lt;li&gt;The value is \(1.000\dots001_2 \times 2^1 = (1 + 2^{-23}) \times 2 = 2 + 2^{-22}\).&lt;/li&gt;
    &lt;li&gt;Therefore, the smallest number greater than 2 is &lt;strong&gt;\(2 + 2^{-22}\)&lt;/strong&gt; (approximately \(2 + 2.38 \times 10^{-7}\)).&lt;/li&gt;
  &lt;/ul&gt;

&lt;/div&gt;

&lt;div class=&quot;fp-example&quot;&gt;

  &lt;p&gt;&lt;strong&gt;Example 2: What is the largest exact odd integer that can be represented?&lt;/strong&gt;&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;To represent an exact integer, the fractional part must completely cover the integer bits without any fractional remainder.&lt;/li&gt;
    &lt;li&gt;Single precision has 24 bits of precision (1 implicit + 23 explicit).&lt;/li&gt;
    &lt;li&gt;The largest integer where the spacing between representable numbers is exactly 1 occurs when the exponent pushes the radix point perfectly to the end of the 23-bit fraction.&lt;/li&gt;
    &lt;li&gt;This happens when \(E - 127 = 23 \implies \text{Exponent} = 150\).&lt;/li&gt;
    &lt;li&gt;The form is \(1.\text{Fraction} \times 2^{23}\).&lt;/li&gt;
    &lt;li&gt;The maximum value of this form is \(1.111\dots111_2 \times 2^{23} = 2^{24} - 1 = 16,777,215\).&lt;/li&gt;
    &lt;li&gt;What if we go larger? At \(E - 127 = 24\), the value is \(1.F \times 2^{24}\). The least significant bit now represents \(2^{-23} \times 2^{24} = 2^1 = 2\). This means numbers in this range can only represent &lt;strong&gt;EVEN&lt;/strong&gt; integers (the spacing is 2).&lt;/li&gt;
    &lt;li&gt;So, the largest odd integer in single precision is &lt;strong&gt;\(2^{24} - 1 = 16,777,215\)&lt;/strong&gt;. (For double precision, it is \(2^{53} - 1 = 9,007,199,254,740,991\)).&lt;/li&gt;
  &lt;/ul&gt;

&lt;/div&gt;

&lt;h2 id=&quot;8-how-does-the-computer-actually-calculate&quot;&gt;8. How Does the Computer Actually Calculate?&lt;/h2&gt;

&lt;p&gt;The underlying philosophy for calculations is to &lt;strong&gt;reduce complex operations to integer math and polynomial approximations.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;addition--and-subtraction--&quot;&gt;Addition (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt;) and Subtraction (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt;)&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Alignment:&lt;/strong&gt; The CPU right-shifts the fraction of the number with the smaller exponent until both exponents match.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Integer Math:&lt;/strong&gt; The fractions are fed into the &lt;strong&gt;exact same two’s complement adder circuit&lt;/strong&gt; used for integers.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Normalization:&lt;/strong&gt; The CPU shifts the fraction back into the \(1.\text{xxx}\) format and adjusts the exponent accordingly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Warning:&lt;/em&gt; Subtracting two very close numbers causes &lt;strong&gt;catastrophic cancellation&lt;/strong&gt;, where significant bits cancel out, instantly destroying precision.&lt;/p&gt;

&lt;h3 id=&quot;multiplication--and-division-&quot;&gt;Multiplication (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt;) and Division (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Multiply:&lt;/strong&gt; Multiply the fractions (using an integer multiplier) and &lt;strong&gt;add&lt;/strong&gt; the exponents (subtracting one bias, since both exponents inherently included a bias).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Divide:&lt;/strong&gt; Divide the fractions and &lt;strong&gt;subtract&lt;/strong&gt; the exponents (adding back one bias).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;exponentiation-ex-and-logarithm-ln-x&quot;&gt;Exponentiation (\(e^x\)) and Logarithm (\(\ln x\))&lt;/h3&gt;

&lt;p&gt;The floating-point format (\(1.F \times 2^{E-\text{Bias}}\)) is &lt;em&gt;already&lt;/em&gt; an exponential function!&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Exponent (\(e^x\)):&lt;/strong&gt; Using the identity \(e^x = 2^{x / \ln 2}\), the integer part of the result is &lt;strong&gt;directly added to the exponent (\(E\)) field&lt;/strong&gt; (fast integer addition!). The tiny fractional part is calculated using a minimax polynomial.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Logarithm (\(\ln x\)):&lt;/strong&gt; Since \(\ln(x) = \ln(1.F) + (E-\text{Bias})\ln(2)\), the \((E-\text{Bias})\) term is extracted via simple integer arithmetic. The CPU only needs to approximate \(\ln(1.F)\) using polynomials.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;power-xy&quot;&gt;Power (\(x^y\))&lt;/h3&gt;

&lt;p&gt;This is calculated as \(x^y = e^{y \cdot \ln(x)}\) by calling the highly optimized hardware or software &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;log&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exp&lt;/code&gt; functions.&lt;/p&gt;

&lt;h3 id=&quot;trigonometric-functions-sin-cos&quot;&gt;Trigonometric Functions (\(\sin\), \(\cos\))&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Range Reduction:&lt;/strong&gt; The input is reduced (e.g., \(x \bmod (\pi/2)\)). This requires an incredibly precise stored value of \(\pi\) to avoid massive errors for large inputs (e.g., using the Payne-Hanek algorithm).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Polynomial Approximation:&lt;/strong&gt; The reduced input is evaluated using a minimax polynomial (like a Chebyshev series) via hardware &lt;strong&gt;FMA (Fused Multiply-Add)&lt;/strong&gt; instructions, which calculate \((A \times B) + C\) in a single cycle without intermediate rounding errors.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;9-epilogue-twos-complement-and-hexadecimal&quot;&gt;9. Epilogue: Two’s Complement and Hexadecimal&lt;/h2&gt;

&lt;p&gt;To fully appreciate floating-point design, we must contrast it with how standard integers are stored.&lt;/p&gt;

&lt;h3 id=&quot;why-do-integers-use-twos-complement&quot;&gt;Why do Integers use Two’s Complement?&lt;/h3&gt;

&lt;p&gt;While floating-point exponents use a &lt;strong&gt;Bias&lt;/strong&gt; to preserve their raw sorting order, standard signed integers use &lt;strong&gt;Two’s Complement&lt;/strong&gt;. Why?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Unified Adder/Subtractor:&lt;/strong&gt; The biggest advantage is that \(A - B\) literally becomes \(A + (\text{Two&apos;s Complement of } B)\). The CPU only needs to build a single fast addition circuit (ALU) to handle both addition and subtraction.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;What about Multipliers and Dividers?&lt;/strong&gt; Do they share circuits too? Yes! Integer multipliers use arrays of adders (partial products). Two’s complement allows the exact same core multiplier hardware to be used for signed numbers with only minor sign-extension tweaks (like Booth’s multiplication algorithm). Dividers (like non-restoring division) also seamlessly leverage the same add/subtract ALU.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Single Zero:&lt;/strong&gt; Unlike “Sign-and-Magnitude” encoding, Two’s complement has only one representation for \(0\) (no \(+0\) and \(-0\)), preventing bugs in software &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if (x == 0)&lt;/code&gt; checks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;why-do-we-always-read-memory-in-hexadecimal-hex&quot;&gt;Why do we always read memory in Hexadecimal (Hex)?&lt;/h3&gt;

&lt;p&gt;You will often see 32-bit floats or integers printed as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x40490FDB&lt;/code&gt; instead of a massive 32-digit binary string.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Perfect mapping:&lt;/strong&gt; Binary is too long for humans to read, and converting back and forth between Base-10 and Base-2 is computationally annoying. But Base-16 (Hexadecimal) is the perfect middle ground because \(16 = 2^4\).&lt;/li&gt;
  &lt;li&gt;Exactly &lt;strong&gt;4 binary bits map directly to exactly 1 Hex character&lt;/strong&gt; (\(0000_2 = \text{0}_{16}\) through \(1111_2 = \text{F}_{16}\)).&lt;/li&gt;
  &lt;li&gt;We can instantly break an 8-bit byte into two 4-bit “nibbles”, represented cleanly by 2 Hex digits. Hex is not a new number format; it is simply a highly readable, compact way for humans to look at pure binary!&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>CARLA Simulator on WSL2: Resolving the Docker Vulkan Trap</title>
    <link href="https://yuhanchi.github.io/writing/carla-wsl2/"/>
    <id>https://yuhanchi.github.io/writing/carla-wsl2/</id>
    <updated>2026-05-31T00:00:00+08:00</updated><summary>A guide on setting up a robust Windows-WSL2 hybrid simulation environment for CARLA 0.9.16, alongside a detailed root-cause analysis of Vulkan rendering crashes in WSL2 Docker.</summary>
    <content type="html">&lt;h2 id=&quot;1-system--hardware-specifications&quot;&gt;1. System &amp;amp; Hardware Specifications&lt;/h2&gt;

&lt;p&gt;The configuration and environment details used:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Host OS:&lt;/strong&gt; Windows 11&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;WSL2 Distro:&lt;/strong&gt; Ubuntu 24.04 LTS (Kernel: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6.6.87.2-microsoft-standard-WSL2&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;GPU:&lt;/strong&gt; NVIDIA GeForce RTX 5060 Laptop (8GB VRAM, Host Driver: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;592.27&lt;/code&gt;, CUDA &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;13.1&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Docker:&lt;/strong&gt; Docker Desktop &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4.63.0&lt;/code&gt; (Engine &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;29.2.1&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CARLA Version:&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.9.16&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;2-the-working-solution-windows-server--wsl2-client-hybrid-architecture&quot;&gt;2. The Working Solution: Windows Server + WSL2 Client Hybrid Architecture&lt;/h2&gt;

&lt;p&gt;Instead of fighting virtualization layers and containerized Vulkan driver mapping, the most performant and stable approach for CARLA on WSL2 is a &lt;strong&gt;hybrid architecture&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;CARLA Server runs natively on Windows:&lt;/strong&gt; Gives Unreal Engine 4 direct, high-performance access to the host GPU (RTX 5060) for 3D rendering and physics.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CARLA Client runs inside WSL2:&lt;/strong&gt; Keeps the Python development, training pipelines, and model libraries in the native Linux environment.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;┌─────────────────────────────────────────────┐
│  Windows Host (Direct GPU Access)           │
│  CARLA Simulator Server (CarlaUE4.exe)      │
│  Listens on Port 2000                       │
│  Handles: 3D Rendering, Physics, Autopilot  │
└──────────────────┬──────────────────────────┘
                   │
                   │ Network (127.0.0.1:2000)
                   │
┌──────────────────▼──────────────────────────┐
│  WSL2 (Ubuntu 24.04 Dev Environment)        │
│  Python Client (carenv Conda Environment)   │
│  Handles: Agent Logic, RL training, Sensors │
└─────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;installation-steps&quot;&gt;Installation Steps&lt;/h3&gt;

&lt;h4 id=&quot;step-1-windows-side-setup&quot;&gt;Step 1: Windows Side Setup&lt;/h4&gt;
&lt;ol&gt;
  &lt;li&gt;Download &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CARLA_0.9.16Windows.zip&lt;/code&gt; from the &lt;a href=&quot;https://github.com/carla-simulator/carla/releases/tag/0.9.16&quot;&gt;CARLA GitHub Releases&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Extract the zip file to your preferred directory (referred to as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;CARLA_PATH&amp;gt;&lt;/code&gt; here, e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\CARLA_0.9.16&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;Install the required dependencies:
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;DirectX End-User Runtime:&lt;/strong&gt; Download and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dxwebsetup.exe&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Visual C++ Redistributable 2015-2022 (x64):&lt;/strong&gt; Download and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VC_redist.x64.exe&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;step-2-wsl2-side-setup&quot;&gt;Step 2: WSL2 Side Setup&lt;/h4&gt;
&lt;p&gt;Create and activate a conda environment for the CARLA client:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda create &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; carenv &lt;span class=&quot;nv&quot;&gt;python&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3.10 &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt;
conda activate carenv
pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;carla
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Verify the installation:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;import carla; print(&apos;CARLA client package successfully installed!&apos;)&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;step-3-network-configuration-mirrored-mode&quot;&gt;Step 3: Network Configuration (Mirrored Mode)&lt;/h4&gt;
&lt;p&gt;To ensure seamless network communication between WSL2 and Windows via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;127.0.0.1&lt;/code&gt;, enable &lt;strong&gt;Mirrored mode&lt;/strong&gt; in WSL2.&lt;/p&gt;

&lt;p&gt;Create or edit your Windows user profile configuration file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%USERPROFILE%\.wslconfig&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;[wsl2]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;networkingMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;mirrored&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then, restart WSL2 from a Windows PowerShell terminal to apply the changes:&lt;/p&gt;
&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;wsl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--shutdown&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;3-running-the-simulation&quot;&gt;3. Running the Simulation&lt;/h2&gt;

&lt;h3 id=&quot;step-1-start-the-carla-server-windows&quot;&gt;Step 1: Start the CARLA Server (Windows)&lt;/h3&gt;
&lt;p&gt;Open a Windows PowerShell terminal and start the server:&lt;/p&gt;
&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;cd&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;CARLA_PATH&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# Options:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# 1. With visual window (default)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;\CarlaUE4.exe&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# 2. Headless mode (no visual output, lower VRAM overhead)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;\CarlaUE4.exe&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-RenderOffScreen&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-nosound&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# 3. Custom window resolution&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;\CarlaUE4.exe&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-windowed&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-ResX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1280&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-ResY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;720&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-2-run-python-client-scripts-wsl2&quot;&gt;Step 2: Run Python Client Scripts (WSL2)&lt;/h3&gt;
&lt;p&gt;Once the server is running on the Windows side, launch the client scripts inside WSL2:&lt;/p&gt;

&lt;h4 id=&quot;1-connection-test-test_connectionpy&quot;&gt;1. Connection Test (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test_connection.py&lt;/code&gt;)&lt;/h4&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;CARLA 连接测试脚本 - 从 WSL2 连接 Windows CARLA 服务端&quot;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;carla&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;carla&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;127.0.0.1&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Server version: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_server_version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Client version: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_client_version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;可用地图: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_available_maps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;world&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;当前地图: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;当前 actors 数量: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_actors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;连接测试通过!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;2-spawn-and-control-vehicle-spawn_vehiclepy&quot;&gt;2. Spawn and Control Vehicle (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spawn_vehicle.py&lt;/code&gt;)&lt;/h4&gt;
&lt;p&gt;This script spawns a Tesla Model 3, attaches a front-facing camera, enables autopilot, and saves camera frames to a local folder for 10 seconds:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;CARLA 生成车辆 + 摄像头截图&quot;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;carla&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;random&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;OUTPUT_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;output&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;makedirs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OUTPUT_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exist_ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 连接
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;carla&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;127.0.0.1&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;world&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 获取蓝图库
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blueprint_library&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_blueprint_library&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 找一个车辆蓝图
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vehicle_bp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blueprint_library&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;vehicle.tesla.model3&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;spawn_points&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_spawn_points&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;spawn_point&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spawn_points&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 生成车辆
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vehicle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spawn_actor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vehicle_bp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spawn_point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;车辆已生成: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vehicle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type_id&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; at &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spawn_point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 添加摄像头传感器
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;camera_bp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blueprint_library&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;sensor.camera.rgb&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;camera_bp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;image_size_x&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;800&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;camera_bp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;image_size_y&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;600&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;camera_bp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;fov&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;90&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 摄像头放在车顶上方
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;camera_transform&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;carla&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;carla&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;camera&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spawn_actor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;camera_bp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;camera_transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attach_to&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vehicle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;摄像头已挂载&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 保存截图计数
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;frame_count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;save_image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;frame_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;filepath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OUTPUT_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;frame_&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;frame_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;04&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save_to_disk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filepath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;截图保存: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filepath&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;camera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save_image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 让车辆自动驾驶
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vehicle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_autopilot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;自动驾驶已开启&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 运行 10 秒，采集截图
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;开始采集，运行 10 秒...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 清理
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;camera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;camera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;vehicle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;完成! 共采集 &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;frame_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; 帧截图，保存在 &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OUTPUT_DIR&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;4-the-failed-path-running-carla-inside-wsl2-docker-troubleshooting-record&quot;&gt;4. The Failed Path: Running CARLA inside WSL2 Docker (Troubleshooting Record)&lt;/h2&gt;

&lt;p&gt;For completeness, below is a record of our attempts to run CARLA directly inside a WSL2 Docker container, and why it consistently failed.&lt;/p&gt;

&lt;h3 id=&quot;attempted-run-configurations&quot;&gt;Attempted Run Configurations&lt;/h3&gt;

&lt;h4 id=&quot;attempt-1-basic-gpu-enabled-container&quot;&gt;Attempt 1: Basic GPU-enabled Container&lt;/h4&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; carla &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--gpus&lt;/span&gt; all &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;host &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;NVIDIA_VISIBLE_DEVICES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;all &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;NVIDIA_DRIVER_CAPABILITIES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;all &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    carlasim/carla:0.9.16 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    bash CarlaUE4.sh &lt;span class=&quot;nt&quot;&gt;-RenderOffScreen&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-nosound&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Result:&lt;/strong&gt; The engine complains: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WARNING: lavapipe is not a conformant vulkan implementation&lt;/code&gt;. After 60 seconds, it crashes with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GameThread timed out waiting for RenderThread&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;attempt-2-mount-host-vulkan-icd-file&quot;&gt;Attempt 2: Mount Host Vulkan ICD File&lt;/h4&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; carla &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--gpus&lt;/span&gt; all &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;host &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;NVIDIA_VISIBLE_DEVICES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;all &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;NVIDIA_DRIVER_CAPABILITIES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;all &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;VK_ICD_FILENAMES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/share/vulkan/icd.d/nvidia_icd.json &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; /usr/share/vulkan/icd.d:/usr/share/vulkan/icd.d:ro &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    carlasim/carla:0.9.16 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    bash CarlaUE4.sh &lt;span class=&quot;nt&quot;&gt;-RenderOffScreen&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-nosound&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Result:&lt;/strong&gt; Immediate Segmentation Fault.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;attempt-3-using-the-official---runtimenvidia-flag&quot;&gt;Attempt 3: Using the Official &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--runtime=nvidia&lt;/code&gt; Flag&lt;/h4&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; carla &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nvidia &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;host &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;NVIDIA_VISIBLE_DEVICES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;all &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;NVIDIA_DRIVER_CAPABILITIES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;all &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    carlasim/carla:0.9.16 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    bash CarlaUE4.sh &lt;span class=&quot;nt&quot;&gt;-RenderOffScreen&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-nosound&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Result:&lt;/strong&gt; The same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lavapipe&lt;/code&gt; warning, followed by a render thread timeout crash after 60 seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;attempt-4-forcing-opengl-mode&quot;&gt;Attempt 4: Forcing OpenGL Mode&lt;/h4&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; carla &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--gpus&lt;/span&gt; all &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;host &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;NVIDIA_VISIBLE_DEVICES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;all &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;NVIDIA_DRIVER_CAPABILITIES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;all &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;DISPLAY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;:0 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    carlasim/carla:0.9.16 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    bash CarlaUE4.sh &lt;span class=&quot;nt&quot;&gt;-RenderOffScreen&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-nosound&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-opengl&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Result:&lt;/strong&gt; Crash. WSL2 does not expose a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/dri/&lt;/code&gt; device inside the container, making OpenGL hardware acceleration unavailable.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;root-cause-analysis&quot;&gt;Root Cause Analysis&lt;/h3&gt;

&lt;p&gt;The rendering failure in the container is caused by three layered issues:&lt;/p&gt;

&lt;h4 id=&quot;1-the-nvidia_icdjson-directory-bug&quot;&gt;1. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvidia_icd.json&lt;/code&gt; Directory Bug&lt;/h4&gt;
&lt;p&gt;In Ubuntu 24.04:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;file /usr/share/vulkan/icd.d/nvidia_icd.json
/usr/share/vulkan/icd.d/nvidia_icd.json: directory
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A post-installation package manager bug mistakenly runs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mkdir -p&lt;/code&gt; on the path, converting the configuration JSON file into an empty folder. This breaks standard Vulkan loader lookups.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Fix:&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo rm -rf /usr/share/vulkan/icd.d/nvidia_icd.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;2-missing-vulkan-mapping-libraries-in-wsl2&quot;&gt;2. Missing Vulkan Mapping Libraries in WSL2&lt;/h4&gt;
&lt;p&gt;Even with the JSON path fixed, WSL2 is missing NVIDIA’s Vulkan mapping libraries. Under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/lib/wsl/lib/&lt;/code&gt; (and its Windows host counterpart &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Windows\System32\lxss\lib\&lt;/code&gt;), we can see:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libcuda.so&lt;/code&gt; (CUDA computation works)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libd3d12.so&lt;/code&gt; (DirectX 12 works)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libnvidia-ml.so.1&lt;/code&gt; (nvidia-smi works)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libvulkan_nvidia.so&lt;/code&gt; (❌ &lt;strong&gt;Missing!&lt;/strong&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libGLX_nvidia.so&lt;/code&gt; (❌ &lt;strong&gt;Missing!&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NVIDIA’s host drivers do not map the Vulkan/OpenGL shared libraries into the WSL2 environment for Blackwell-based Laptop GPUs (like the RTX 5060) on host driver version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;592.27&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;3-software-renderer-fallback&quot;&gt;3. Software Renderer Fallback&lt;/h4&gt;
&lt;p&gt;Because no hardware Vulkan/OpenGL drivers are visible to WSL2, the Vulkan loader falls back to &lt;strong&gt;llvmpipe / lavapipe&lt;/strong&gt; (CPU-based software rendering):&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ VK_ICD_FILENAMES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/share/vulkan/icd.d/gfxstream_vk_icd.x86_64.json vulkaninfo &lt;span class=&quot;nt&quot;&gt;--summary&lt;/span&gt;
ERROR: setup_loader_term_phys_devs: Failed to detect any valid GPUs &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;the current config
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;CARLA (based on Unreal Engine 4.26) requires hardware rasterization. Forcing the simulation to render on the CPU leads to massive lag, eventually triggering the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GameThread timed out waiting for RenderThread&lt;/code&gt; watchdog mechanism.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;5-summary-of-tips--troubleshooting&quot;&gt;5. Summary of Tips &amp;amp; Troubleshooting&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;VRAM Optimization:&lt;/strong&gt; The RTX 5060 Laptop has 8GB VRAM. Running CARLA with a visual window in standard mode occupies around &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;7.7GB&lt;/code&gt; of VRAM. If you run out of memory (OOM), run the server with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-quality-level=Low&lt;/code&gt; or run it offscreen (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-RenderOffScreen&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Networking Issues:&lt;/strong&gt; If the client fails to connect to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;127.0.0.1&lt;/code&gt;, check your Windows Firewall settings to ensure port &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2000&lt;/code&gt; is open, and verify that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;networkingMode=mirrored&lt;/code&gt; is active in WSL2.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Docker Cleanup:&lt;/strong&gt; Since Dockerized CARLA is unusable in this setup, free up disk space by removing the unused container image:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker rmi carlasim/carla:0.9.16
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;6-useful-resources&quot;&gt;6. Useful Resources&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://carla.readthedocs.io/en/0.9.16/&quot;&gt;CARLA Official Documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/carla-simulator/carla/issues/5806&quot;&gt;CARLA Issue #5806 (WSL2 Discussion)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/cuda/wsl-user-guide/&quot;&gt;NVIDIA CUDA on WSL Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>When CoT Surface Features Transfer</title>
    <link href="https://yuhanchi.github.io/writing/code-not-text/"/>
    <id>https://yuhanchi.github.io/writing/code-not-text/</id>
    <updated>2026-05-04T00:00:00+08:00</updated><summary>A technical note on measurement non-invariance across math, science, and coding reasoning traces.</summary>
    <content type="html">&lt;p&gt;This note summarizes my project &lt;a href=&quot;https://github.com/Chi-Shan0707/code-not-text&quot;&gt;code-not-text&lt;/a&gt;. The interactive version is here: &lt;a href=&quot;https://chi-shan0707.github.io/code-not-text/demo/&quot;&gt;demo&lt;/a&gt;. The full technical report is here: &lt;a href=&quot;https://github.com/Chi-Shan0707/code-not-text/blob/main/project_report/project_report.pdf&quot;&gt;PDF report&lt;/a&gt;.&lt;/p&gt;

&lt;figure&gt;
  &lt;a href=&quot;/assets/img/posts/cot-math-vs-coding.png&quot; title=&quot;Open full size&quot;&gt;&lt;img src=&quot;/assets/img/posts/cot-math-vs-coding.png&quot; alt=&quot;Two reasoning traces side by side. Left, a correct math solution (AIME24 #1) that proceeds step by step and verifies its answer. Right, an incorrect coding trace (LiveCodeBench-v5 #131) full of hedges such as &apos;but note&apos;, &apos;however&apos; and &apos;but wait&apos;.&quot; width=&quot;2040&quot; height=&quot;1184&quot; loading=&quot;lazy&quot; /&gt;&lt;/a&gt;
  &lt;figcaption&gt;Same model, same feature family, two very different traces. Left: a correct AIME24 solution whose reasoning converges step by step. Right: an incorrect LiveCodeBench-v5 trace that reads fluently but keeps hedging while the logic goes wrong. The AUROC in each title is the domain-level AUROC@100% (math 0.982, coding 0.407). From the &lt;a href=&quot;https://chi-shan0707.github.io/code-not-text/demo/&quot;&gt;interactive demo&lt;/a&gt;; click the image for full size.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&quot;question&quot;&gt;Question&lt;/h2&gt;

&lt;p&gt;Can cheap summaries of a chain-of-thought trace predict whether a solution is correct?&lt;/p&gt;

&lt;p&gt;I study one deliberately narrow feature family: hand-crafted CoT-surface and token-trajectory descriptors. The point is not to test every possible verifier. The point is to ask whether this cheap, interpretable feature family transfers across domains.&lt;/p&gt;

&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;

&lt;p&gt;The experiments use &lt;strong&gt;DeepSeek-R1-0528-Qwen3-8B&lt;/strong&gt; at temperature 1.0 across three domains:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Math:&lt;/strong&gt; AIME24, AIME25, BRUMO25, and HMMT25; &lt;strong&gt;7,680 aligned runs&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Science:&lt;/strong&gt; GPQA-style tasks; &lt;strong&gt;12,672 runs&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Coding:&lt;/strong&gt; LiveCodeBench-v5 tasks; &lt;strong&gt;10,688 runs&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The feature family includes token-confidence summaries, token-trajectory statistics, trajectory continuity, novelty, reflection count, and a small activation-derived descriptor. Evaluation uses problem-grouped splits. I report AoA (AUC-of-AUROC across trace anchors), AUROC@100%, and best-of-N reranking.&lt;/p&gt;

&lt;h2 id=&quot;main-result&quot;&gt;Main Result&lt;/h2&gt;

&lt;p&gt;The same feature family behaves very differently across domains.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Domain&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;AoA&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;AUROC@100%&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Best-of-N=64 pass@1&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Math&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.958&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.982&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;+10.0 pp&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Science&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.799&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.841&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;+8.0 pp&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Coding&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.434&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.407&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;-0.6 pp&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;This is the central finding: the feature family is strong in math, narrower in science, and weak for coding correctness on unseen problems.&lt;/p&gt;

&lt;h2 id=&quot;interpretation&quot;&gt;Interpretation&lt;/h2&gt;

&lt;p&gt;The same feature names do not necessarily measure the same latent construct.&lt;/p&gt;

&lt;p&gt;In math, features such as reflection count and trajectory continuity can track whether reasoning is converging. In science, the signal is more confidence-heavy. In coding, executable correctness is farther away from the surface form of the reasoning trace. A trace can look organized and confident while still implementing the wrong program logic.&lt;/p&gt;

&lt;p&gt;I view this as a measurement non-invariance result: a feature family can be useful in one domain without being a general-purpose correctness proxy.&lt;/p&gt;

&lt;h2 id=&quot;robustness-checks&quot;&gt;Robustness Checks&lt;/h2&gt;

&lt;p&gt;The coding result is not just one failed probe. I tested several possible explanations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;an 83-scalar coding-specific feature sweep,&lt;/li&gt;
  &lt;li&gt;grouped feature ablations,&lt;/li&gt;
  &lt;li&gt;a coding-specific CoT-only judge,&lt;/li&gt;
  &lt;li&gt;nonlinear MLP classifiers,&lt;/li&gt;
  &lt;li&gt;SSL pre-training on 42K unlabeled traces,&lt;/li&gt;
  &lt;li&gt;token-level de-knotting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None produced a strong generalizable coding verifier from this feature family.&lt;/p&gt;

&lt;h2 id=&quot;semantic-knots&quot;&gt;Semantic Knots&lt;/h2&gt;

&lt;p&gt;I also ran a smaller semantic analysis around what I call &lt;strong&gt;semantic knots&lt;/strong&gt;: local places in the visible reasoning prose where the trace appears to lose state control and does not immediately repair itself. Ordinary uncertainty, normal exploration, and clean one-step self-correction do not count.&lt;/p&gt;

&lt;p&gt;This analysis supports the same cross-domain story:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Math:&lt;/strong&gt; knots are common and strongly associated with incorrect answers.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Science:&lt;/strong&gt; knots appear less often, and the correctness relationship is weaker.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Coding:&lt;/strong&gt; knots are rare and do not meaningfully separate correct from incorrect solutions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The de-knotting check is especially useful. Removing knot spans reduces math signal, which suggests that those spans carry failure information. In coding, de-knotting does not reveal a hidden verifier; it leaves the weak signal essentially weak. That is why I read the result as measurement non-invariance rather than a missing preprocessing trick.&lt;/p&gt;

&lt;h2 id=&quot;boundary&quot;&gt;Boundary&lt;/h2&gt;

&lt;p&gt;This does &lt;strong&gt;not&lt;/strong&gt; claim that all text-based verifiers fail. It also does not rule out code-aware models, execution-aware selectors, hidden-state probes, raw-text classifiers, or LLM judges.&lt;/p&gt;

&lt;p&gt;The narrower conclusion is: cheap CoT-surface features are domain-specific measurement instruments, not general-purpose correctness proxies.&lt;/p&gt;

&lt;details&gt;
&lt;summary&gt;Cite this post&lt;/summary&gt;
&lt;p&gt;If you find this post useful in your work, you can cite it as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Chi, Yuhan. “When CoT Surface Features Transfer.” May 4, 2026. &lt;a href=&quot;https://yuhanchi.github.io/writing/code-not-text/&quot;&gt;https://yuhanchi.github.io/writing/code-not-text/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Or use the following BibTeX entry:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bibtex&quot;&gt;@misc{chi2026cot,
  author = {Chi, Yuhan},
  title = {{When CoT Surface Features Transfer}},
  year = {2026},
  month = may,
  howpublished = {Blog post},
  url = {https://yuhanchi.github.io/writing/code-not-text/}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
</content>
  </entry>
</feed>
