Part XII — Modern Sequence Architectures: RoPE, FlashAttention & State-Space Models · Chapter 2

Rotary Position Embedding (RoPE)

Hook

The last chapter ended on a shift-invariant relative bias — a lookup table keyed by distance, bolted onto the score after the fact. What if position could fall out of the dot product itself, with no separate bias term and no embedding ever added to the content? Rotate the query and key instead of translating them, and it does.

Intuition
key fixed at position 0; query rotated to position 0 → dot product = 1.000 (plain dot product would be 1.000)

The key sits fixed at position 0. Step the query's position up and its arrow spins around the origin — the vector's length never changes, only its angle. Watch the dot product: it isn't tracking where the query "is" in any absolute sense, it's tracking how far its angle has swung away from the key's.

Formalize

RoPE rotates a 2D pair of coordinates by an angle proportional to position, before the dot product is ever taken:

R(pos)(xy)=(cos(posθ)sin(posθ)sin(posθ)cos(posθ))(xy)R(pos)\begin{pmatrix}x\\y\end{pmatrix} = \begin{pmatrix}\cos(pos\cdot\theta) & -\sin(pos\cdot\theta)\\ \sin(pos\cdot\theta) & \cos(pos\cdot\theta)\end{pmatrix}\begin{pmatrix}x\\y\end{pmatrix}
  • pospos — the token's position in the sequence.
  • θ\theta — the fixed angular rate: how many radians the pair rotates per position step.
  • R(pos)R(pos) — the rotation matrix applied to that coordinate pair before the dot product.
  1. Rotation preserves length, and preserves relative angle

    RR is orthogonal: it never stretches a vector, only turns it. Turning two vectors by the same angle leaves the angle between them — and so their dot product — completely unchanged.

  2. Turning them by different amounts is the same as turning one by the difference

    R(a)qR(b)k=qR(ba)kR(a)q \cdot R(b)k = q \cdot R(b-a)k. The rotated dot product between a query at position aa and a key at position bb is identical to rotating the key alone by bab-a and leaving the query untouched. Only the difference of the two positions ever enters the calculation.

  3. A real model repeats this across many frequency pairs

    Full RoPE splits the embedding into d/2d/2 coordinate pairs, each with its own θ\theta — exactly the geometric spacing of frequencies from the sinusoidal scheme, just used to rotate instead of to add. This demo uses one pair to keep every angle exact and checkable by hand.

Play
position = 0.00 → dot product = 1.000

Slide the query's position continuously. The key stays anchored at position 0, so the angle swept by the slider is the relative distance — and the dot product it produces depends on nothing else. At θ=π/2\theta = \pi/2, four steps is a full turn: the vector — and the dot product — returns exactly to where it started every four positions.

Worked example

Q0=(1,0.5)Q_0=(1,\,0.5), K0=(0.5,1)K_0=(0.5,\,1), θ=π/2\theta = \pi/2 (a quarter turn per position step):

  1. Distance 0: the plain dot product

    Q0K0=1(0.5)+0.5(1)=1.0Q_0\cdot K_0 = 1(0.5) + 0.5(1) = 1.0. With no rotation at all, this is just the ordinary dot product.

  2. Distance 2: rotate the key by a half turn

    cos(π)=1\cos(\pi)=-1, sin(π)=0\sin(\pi)=0, so R(π)K0=(0.5(1)1(0), 0.5(0)+1(1))=(0.5,1)R(\pi)K_0 = (0.5(-1) - 1(0),\ 0.5(0) + 1(-1)) = (-0.5,\,-1). Then Q0R(π)K0=1(0.5)+0.5(1)=1.0Q_0\cdot R(\pi)K_0 = 1(-0.5)+0.5(-1) = -1.0.

  3. Same distance, different absolute positions — identical answer

    Query at position 1, key at position 3 (still 2 apart):

    • cos(π/2)=0\cos(\pi/2)=0, sin(π/2)=1\sin(\pi/2)=1, so R(π/2)Q0=(1(0)0.5(1), 1(1)+0.5(0))=(0.5,1)R(\pi/2)Q_0 = (1(0) - 0.5(1),\ 1(1) + 0.5(0)) = (-0.5,\,1)
    • cos(3π/2)=0\cos(3\pi/2)=0, sin(3π/2)=1\sin(3\pi/2)=-1, so R(3π/2)K0=(0.5(0)1(1), 0.5(1)+1(0))=(1,0.5)R(3\pi/2)K_0 = (0.5(0) - 1(-1),\ 0.5(-1) + 1(0)) = (1,\,-0.5)

    Their dot product: (0.5)(1)+(1)(0.5)=1.0(-0.5)(1)+(1)(-0.5) = -1.0 — exactly matching the distance-2 score computed from positions 0 and 2.

Checkpoint

The key sits at position 0. Find the query position, among the candidates, that makes the RoPE dot product land within 0.05 of -1.00 — the value a relative distance of 2 produces.

Pick a position to try it
Summary
R(a)qR(b)k=qR(ba)kR(a)q \cdot R(b)k = q \cdot R(b-a)k

Rotating a query and key by an angle proportional to position makes their dot product depend only on the difference of the two angles — the relative distance between them — never on either position by itself. That's relative position falling directly out of the geometry, with no added embedding and no separate bias table to look up. It's also exactly why RoPE runs into trouble past the sequence lengths it was trained on: push posθpos\cdot\theta far enough and the model is rotating into angles it never saw during training. The next chapter is about stretching that trained range without retraining at all.