Skip to main content
1

Prerequisites

You need Go 1.23 or later. Check your installed version:
go version
If you need to install or upgrade Go, see go.dev/dl.
2

Install

Add q to your Go module:
go get github.com/itsubaki/q
No additional setup is required. The library has zero external dependencies.
3

Bell state

A Bell state is the simplest example of quantum entanglement. Two qubits start in |0⟩|0⟩, a Hadamard gate puts the first qubit into superposition, and a CNOT gate entangles both qubits together.
package main

import (
    "fmt"

    "github.com/itsubaki/q"
)

func main() {
    qsim := q.New()

    // generate qubits of |0>|0>
    q0 := qsim.Zero()
    q1 := qsim.Zero()

    // apply quantum circuit
    qsim.H(q0)
    qsim.CNOT(q0, q1)

    for _, s := range qsim.State() {
        fmt.Println(s)
    }

    // [00][  0]( 0.7071 0.0000i): 0.5000
    // [11][  3]( 0.7071 0.0000i): 0.5000

    m0 := qsim.Measure(q0)
    m1 := qsim.Measure(q1)
    fmt.Println(m0.Equal(m1)) // always true

    for _, s := range qsim.State() {
        fmt.Println(s)
    }

    // [00][  0]( 1.0000 0.0000i): 1.0000
    // or
    // [11][  3]( 1.0000 0.0000i): 1.0000
}
Reading the output: Before measurement, qsim.State() shows two lines — [00] and [11] each with probability 0.5000. This is the superposition: the system is in both states simultaneously. After calling Measure(), the state collapses to exactly one outcome. Because the qubits are entangled, m0 and m1 are always equal — measuring one instantly determines the other.Each state line has the format [binary][index](real imaginary i): probability.
4

Quantum teleportation

Quantum teleportation transfers an unknown quantum state from one qubit to another using entanglement and classical communication. Alice holds phi (the state to teleport) and q0. Bob holds q1. After the protocol, q1 holds an exact copy of the original phi state.
package main

import (
    "fmt"

    "github.com/itsubaki/q"
)

func main() {
    qsim := q.New()

    // generate qubits of |phi>|0>|0>
    phi := qsim.New(1, 2)
    q0 := qsim.Zero()
    q1 := qsim.Zero()

    // |phi> is normalized. |phi> = a|0> + b|1>, |a|^2 = 0.2, |b|^2 = 0.8
    for _, s := range qsim.State(phi) {
        fmt.Println(s)
    }

    // [0][  0]( 0.4472 0.0000i): 0.2000
    // [1][  1]( 0.8944 0.0000i): 0.8000

    qsim.H(q0)
    qsim.CNOT(q0, q1)
    qsim.CNOT(phi, q0)
    qsim.H(phi)

    // Alice sends mz, mx to Bob
    mz := qsim.Measure(phi)
    mx := qsim.Measure(q0)

    // Bob Applies X and Z
    qsim.CondX(mx.IsOne(), q1)
    qsim.CondZ(mz.IsOne(), q1)

    // Bob got |phi> state with q1
    for _, s := range qsim.State(q1) {
        fmt.Println(s)
    }

    // [0][  0]( 0.4472 0.0000i): 0.2000
    // [1][  1]( 0.8944 0.0000i): 0.8000
}
The state printed for q1 at the end is identical to the original phi state: amplitude 0.4472 for |0⟩ (probability 0.2) and 0.8944 for |1⟩ (probability 0.8). The state was teleported successfully.qsim.State(phi) accepts one or more qubit arguments to show the reduced state of a specific register rather than the full system.
Most simulator methods return *Q, so you can chain gate calls on a single line:
qsim.H(q0).CNOT(q0, q1)

Build docs developers (and LLMs) love