Skip to content

Phase and interference ​

Phase is the hidden variable of quantum games. It doesn't change what you'll measure. It changes what the next gate that mixes values does with the property. A phase gate alone is invisible to measurement, but followed by a superpose() or an interaction, it redistributes probability through interference.

Clock gate: rotating phase ​

The clock gate adds phase to a property. phase() and z() are the same call:

typescript
import { ensureLoaded, quantum } from "quantum-forge/quantum";

await ensureLoaded();

const coin = quantum([false, true]).superpose();
coin.phase(0.5);   // a π/2 phase on true
coin.phase(0.25);  // a π/4 phase on true
coin.phase();      // the discrete gate: Pauli Z at dimension 2

On a qubit, phase(f) turns the phase of true by f × π, so to turn it by an angle in radians, pass angle / Math.PI. Leave the fraction out for the discrete gate. See Gates: fractional gates.

After a phase gate, coin.probabilities() returns the same values. The phase is invisible until the property meets a gate that mixes values.

Phase shows at the next mixing gate ​

The smallest example is a qubit and two Hadamards:

typescript
const plain = quantum([false, true]).superpose().superpose();
// plain ends at false, every time

const phased = quantum([false, true]).superpose().phase().superpose();
// phased ends at true, every time

Both properties had the same probabilities between the two superpose() calls. The phase decided which way the second superpose() sent them. That is interference: in the first case the two paths to false add up and the paths to true cancel; the phase flips which ones cancel.

Phase + iSwap = probability redistribution ​

This is the core mechanic of Quantum Pong: split, apply phase to one ball, then let the pair interact again. The phase between the two interactions decides where the probability goes.

typescript
const a = quantum([false, true]).flip(); // exists
const b = quantum([false, true]);        // does not
a.iSwap(b, 0.5);                         // split
a.phase(bias);                           // bias from 0 to 1; 0.5 is a π/2 phase on true
a.iSwap(b, 0.5);                         // interact again: the phase now moves probability
biasa.probability(true) after the second iSwap
00
0.50.5
11

A phase before a single split changes nothing. Apply a.phase(bias) before the first iSwap and each ball still exists with probability 1/2. The phase needs a later mixing gate to turn into probability. In the same way, a phase on a ball does not change what its next split with a fresh ball gives; it only steers the partner it is already entangled with.

In Quantum Pong the paddle sets the bias: a hit turns the ball's phase dial, and the next time the ball meets its entangled partner, that phase decides which of the two is more likely to exist.

Grover oracle pattern ​

Used by: Hex Diffusion

The Grover oracle marks specific values with a π phase flip, then a diffusion step (a small Hadamard) converts that phase difference into a probability difference. Marked values become "walls" that probability moves away from.

typescript
import { phaseRotate } from "quantum-forge/quantum";

// Mark the "wall" value with a π phase
phaseRotate(Math.PI, { when: [hex.is(wallState)] });

// Diffusion step spreads probability
hex.superpose(0.1); // fractional Hadamard for gradual diffusion

On a qutrit in equal superposition, marking one value this way and then running superpose(0.1) leaves that value below its starting 1/3, and lower than the same diffusion step gives without the mark. Probability moves off the marked value through destructive interference.

If you build the predicate list dynamically, check that it isn't empty before calling phaseRotate. An empty when list does nothing and raises nothing, so a marking pass that selects nothing looks exactly like one that ran.

This is Grover's search algorithm repurposed as a game mechanic.

Visualizing phase ​

Phase is invisible to measurement but visible in the density matrix. Games extract and display it in different ways.

Quantum Pong: phase dial ​

The phase dial shows the relative phase between two entangled balls as a rotating indicator:

typescript
import { densityMatrix } from "quantum-forge/quantum";

const entry = densityMatrix(ballA.exists, ballB.exists).find(
  (e) => e.row[0] === true && e.row[1] === false &&
         e.col[0] === false && e.col[1] === true,
);
const phase = entry ? Math.atan2(entry.imag, entry.real) : 0;
// phase: -π to π radians. Map it to the dial's rotation angle
dialAngle = phase;

Right after a split this reads -π/2. ballA.exists.phase(angle / Math.PI) turns it by angle.

Bloch Invaders: color hue ​

The Bloch sphere picture maps a qubit's phase to hue:

typescript
const entry = densityMatrix(invader.state).find(
  (e) => e.row[0] === true && e.col[0] === false,
);
const phi = entry ? Math.atan2(entry.imag, entry.real) : 0;
// Map phi to an HSL hue for the invader's glow color
invaderHue = (phi / (2 * Math.PI) + 0.5) * 360;

Ponq: coherence-driven forces ​

The magnitude of the off-diagonal entry is the coherence: how much the property is "in superposition" rather than collapsed. Ponq uses it as a physics force:

typescript
const offDiag = densityMatrix(ball.state).find((e) => e.row[0] !== e.col[0]);
const coherence = offDiag ? Math.hypot(offDiag.real, offDiag.imag) : 0;
// coherence: 0 (collapsed) to 0.5 (equal superposition)
steeringForce = coherence * MAX_FORCE;

A measured property has no off-diagonal entry at all, so treat a missing entry as zero coherence.

Quantris: compass display ​

Phase mapped to a compass direction on quantum pieces:

typescript
const phase = pieceRelativePhase(piece); // from densityMatrix, as above
compassDirection = phase;                // drawn as an arrow on the piece

Phase rotation reference ​

For phaseRotate(angle, { when }), or phase(angle / Math.PI) on a qubit:

AngleEffectName
0No changeIdentity
π/4Subtle biasT gate equivalent
π/2Quarter turnS gate equivalent
πFull flipZ gate equivalent
2πFull circleBack to identity

Key insight ​

Phase is the "control knob" that lets players influence quantum outcomes without choosing them outright. The player can't pick which ball exists, but they can bias the odds by applying phase between two interactions. This creates a skill gap: experienced players learn to use phase strategically, while the quantum randomness keeps outcomes surprising.

Powered by Quantum Forge