qubit-gates-in-c
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| qubit-gates-in-c [February 19, 2026 at 12:20] – yanevskiv | qubit-gates-in-c [May 14, 2026 at 11:38] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | # Qubit gate | ||
| + | ## Simulation | ||
| + | In C99, a header [[complex.h|< | ||
| + | |||
| + | ### State | ||
| + | As we've seen, a qubit is a two-state configuration with complex probability amplitudes distributed between the two states. | ||
| + | This gives us the following implementation of a single qubit: | ||
| + | $$\lvert\psi\rangle = \alpha\lvert 0\rangle + \beta\lvert 1\rangle, | ||
| + | ```c | ||
| + | #include < | ||
| + | |||
| + | typedef struct { | ||
| + | double complex a; // alpha | ||
| + | double complex b; // beta | ||
| + | } qubit_t; | ||
| + | ``` | ||
| + | |||
| + | |||
| + | ### Norm (Born rule) | ||
| + | $$\lVert\psi\lVert^2 = |\alpha|^2 + |\beta|^2 = \alpha\bar{\alpha} + \beta\bar{\beta}$$ | ||
| + | ```c | ||
| + | double qubit_norm2(qubit_t psi) | ||
| + | { | ||
| + | return creal(psi.a * conj(psi.a) + psi.b * conj(psi.b)) | ||
| + | } | ||
| + | ``` | ||
| + | |||
| + | ### Normalization | ||
| + | $$\lvert\psi\rangle\rightarrow\frac{\lvert\psi\rangle}{\sqrt{\langle\psi\lvert\psi\rangle}}$$ | ||
| + | ```c | ||
| + | qubit_t qubit_normalize(qubit_t psi) | ||
| + | { | ||
| + | double norm = sqrt(qubit_norm2(psi)); | ||
| + | return norm == 0.0 ? psi : { psi.a / norm, psi.b / norm }; | ||
| + | } | ||
| + | ``` | ||
| + | |||
| + | ### Inner product | ||
| + | $$\langle\phi\lvert\psi\rangle = \overline{\phi_\alpha}\psi_\alpha + \overline{\phi_\beta}\psi_\beta$$ | ||
| + | ```c | ||
| + | double complex qubit_inner(qubit_t phi, qubit_t psi) | ||
| + | { | ||
| + | return conj(phi.a) * psi.a + conj(phi.b) * psi.b; | ||
| + | } | ||
| + | ``` | ||
| + | |||
| + | ### Measurement probabilities (Born rule) | ||
| + | $$P(0) = |\alpha|^2 = \alpha\bar{\alpha}$$ | ||
| + | |||
| + | ```c | ||
| + | double qubit_prob0(qubit_t psi) | ||
| + | { | ||
| + | return creal(psi.a * conj(psi.a)); | ||
| + | } | ||
| + | ``` | ||
| + | $$P(1) = |\beta|^2 = \beta\bar{\beta}$$ | ||
| + | ```c | ||
| + | double qubit_prob1(qubit_t psi) | ||
| + | { | ||
| + | return creal(psi.b * conj(psi.b)); | ||
| + | } | ||
| + | ``` | ||
| + | |||
| + | ### Projective measurement (collapse) | ||
| + | $$\lvert\psi\rangle\rightarrow\frac{P_i\lvert\psi\rangle}{\sqrt{\langle\psi\lvert P_i\lvert\psi\rangle}}$$ | ||
| + | $$P_0 = \lvert 0\rangle\langle 0\lvert$$ | ||
| + | $$P_1 = \lvert 1\rangle\langle 1\lvert$$ | ||
| + | ```c | ||
| + | #define C_ONE (1.0 + I * 0.0) | ||
| + | #define C_ZERO (0.0 + I * 0.0) | ||
| + | qubit_t qubit_measure(qubit_t psi) | ||
| + | { | ||
| + | double r = (double)rand() / RAND_MAX; | ||
| + | if (r < qubit_prob0(psi)) { | ||
| + | return { C_ONE, C_ZERO }; | ||
| + | } else { | ||
| + | return { C_ZERO, C_ONE }; | ||
| + | } | ||
| + | } | ||
| + | ``` | ||
| + | |||
| + | ### Linear operator (unitary gate) | ||
| + | $$U = \begin{pmatrix}u_{00} & u_{01} \\ u_{10} & u_{11} \end{pmatrix}$$ | ||
| + | $$\lvert\psi' | ||
| + | |||
| + | ```c | ||
| + | typedef struct { | ||
| + | double complex u00, u01; | ||
| + | double complex u10, u11; | ||
| + | } gate2_t; | ||
| + | |||
| + | qubit_t gate2_apply(gate2_t U, qubit_t psi) | ||
| + | { | ||
| + | return (qubit_t){ | ||
| + | U.u00 * psi.a + U.u01 * psi.b, | ||
| + | U.u10 * psi.a + U.u11 * psi.b | ||
| + | }; | ||
| + | } | ||
| + | ``` | ||
| + | |||
| + | ### Pauli-X (bit flip) | ||
| + | Pauli-X operator swaps amplitudes. It's a $180^\deg$ rotation around the X-axis of the Bloch sphere. | ||
| + | $$X = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}$$ | ||
| + | ```c | ||
| + | gate2_t gate_X(void) | ||
| + | { | ||
| + | return (gate2_t){ | ||
| + | 0, 1, | ||
| + | 1, 0 | ||
| + | }; | ||
| + | } | ||
| + | ``` | ||
| + | |||
| + | ### Pauli-Z (phase flip) | ||
| + | Pauli-Z operator flips the relative phase. Probabilities remain unchanged, but interference patterns change. | ||
| + | $$Z = \begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix}$$ | ||
| + | ```c | ||
| + | gate2_t gate_Z(void) | ||
| + | { | ||
| + | return (gate2_t){ | ||
| + | 1, 0, | ||
| + | 0, -1 | ||
| + | }; | ||
| + | } | ||
| + | ``` | ||
| + | |||
| + | ### Hadamard (superposition generator) | ||
| + | Hadamard gate mixes the amplitudes evenly. If a qubit is in a pure state $\lvert\psi\rangle = \lvert 0\rangle$, after Hadamard states are evenly mixed $1/ | ||
| + | $$H = \frac{1}{\sqrt{2}}\begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix}$$ | ||
| + | |||
| + | ```c | ||
| + | gate2_t gate_H(void) | ||
| + | { | ||
| + | double s = 1.0 / sqrt(2.0); | ||
| + | return (gate2_t){ | ||
| + | s, s, | ||
| + | s, -s | ||
| + | }; | ||
| + | } | ||
| + | ``` | ||
| + | |||
| + | ### Z-axis rotation | ||
| + | This connects the Schrodinger equation with gate logic. | ||
| + | |||
| + | $$R_z(\theta) = e^{-i\theta\sigma_z/ | ||
| + | |||
| + | ```c | ||
| + | gate2_t gate_Rz(double theta) | ||
| + | { | ||
| + | double complex e_minus = cexp(-I * theta / 2.0); | ||
| + | double complex e_plus | ||
| + | |||
| + | return (gate2_t){ | ||
| + | e_minus, 0, | ||
| + | 0, | ||
| + | }; | ||
| + | } | ||
| + | ``` | ||
| + | |||
| + | ### Global phase invariance | ||
| + | $$\lvert\psi\rangle \sim e^{i\phi}\lvert\psi\rangle$$ | ||
| + | ```c | ||
| + | qubit_t qubit_global_phase(qubit_t psi, double phi) | ||
| + | { | ||
| + | double complex phase = cexp(I * phi); | ||
| + | psi.a *= phase; | ||
| + | psi.b *= phase; | ||
| + | return psi; | ||
| + | } | ||
| + | ``` | ||
| + | |||
| + | ### Bloch sphere parametrization | ||
| + | $$\lvert\psi\rangle = \cos(\theta / 2)\cdot\lvert 0\rangle + e^{i\phi}\sin(\theta/ | ||
| + | ```c | ||
| + | void qubit_to_bloch(qubit_t psi, double *theta, double *phi) | ||
| + | { | ||
| + | psi = qubit_normalize(psi); | ||
| + | |||
| + | double a_mag = cabs(psi.a); | ||
| + | *theta = 2.0 * acos(a_mag); | ||
| + | |||
| + | double arg_a = carg(psi.a); | ||
| + | double arg_b = carg(psi.b); | ||
| + | *phi = arg_b - arg_a; | ||
| + | } | ||
| + | ``` | ||
