Qx (Qx - Quantum Computing Simulator v0.8.0)

View Source

Qx - A Quantum Computing Simulator for Elixir

Qx provides a simple and intuitive API for quantum computing simulations. It supports up to 20 qubits with statevector simulation using Nx as the computational backend for efficient processing.

Example Usage

# Create a Bell state circuit
qc = Qx.create_circuit(2, 2)
|> Qx.h(0)
|> Qx.cx(0, 1)
|> Qx.measure(0, 0)
|> Qx.measure(1, 1)

result = Qx.run(qc)
Qx.draw(result)

Modules

The Qx library consists of several modules:

  • Qx - Main API (this module)
  • Qx.Qubit - Functions for qubit creation and manipulation
  • Qx.QuantumCircuit - Quantum circuit creation and management
  • Qx.Operations - Quantum gate operations, including basis-explicit measurement (measure_x/measure_y/measure_z) and controlled rotations (cy, crx, cry, crz)
  • Qx.Patterns - Composite circuit-building patterns. Each _all helper accepts either no second arg (whole-circuit) or a list/range of qubit indices (sub-register) — e.g. Qx.h_all(qc, 0..2).
  • Qx.Simulation - Circuit execution and simulation
  • Qx.Draw - Visualization of results
  • Qx.Math - Core mathematical functions for quantum mechanics
  • Qx.Export.OpenQASM - Export circuits to OpenQASM for real quantum hardware

Exporting to Real Quantum Hardware

Qx can export circuits to OpenQASM format for execution on real quantum computers:

# Create a Bell state circuit
circuit = Qx.create_circuit(2, 2)
  |> Qx.h(0)
  |> Qx.cx(0, 1)
  |> Qx.measure(0, 0)
  |> Qx.measure(1, 1)

# Export to OpenQASM 3.0
qasm = Qx.Export.OpenQASM.to_qasm(circuit)
File.write!("bell_state.qasm", qasm)

See Qx.Export.OpenQASM for more details and examples.

Summary

Functions

Adds a single barrier instruction spanning every qubit.

Adds a single barrier spanning the given list or range of qubits. See Qx.Patterns.barrier_all/2. Empty list/range is a no-op.

Creates one of the four Bell-state circuits (maximally entangled two-qubit states). See Qx.Patterns.bell_state_circuit/1.

Applies gates conditionally based on a classical bit value.

Applies a controlled-controlled-X (CCNOT/Toffoli) gate.

Applies a controlled-phase (CP) gate.

Creates a new quantum circuit with only qubits (no classical bits).

Creates a new quantum circuit with specified qubits and classical bits.

Applies a controlled rotation about the X-axis. See Qx.Operations.crx/4.

Applies a controlled rotation about the Y-axis. See Qx.Operations.cry/4.

Applies a controlled rotation about the Z-axis. See Qx.Operations.crz/4.

Applies a Fredkin (controlled-SWAP) gate.

Applies a controlled-X (CNOT) gate.

Applies a linear cascade of CNOTs along qubits.

Applies a controlled-Y (CY) gate. See Qx.Operations.cy/3.

Applies a controlled-Z (CZ) gate.

Visualizes probability distribution from simulation results.

Visualizes a single qubit state on the Bloch sphere.

Visualizes measurement counts as a bar chart.

Displays a quantum state as a formatted table.

Gets probability distribution for computational basis states.

Executes a circuit and returns only the final quantum state.

Creates an n-qubit GHZ-state preparation circuit. Default is 3 qubits.

Applies a Hadamard gate to the specified qubit.

Applies a Hadamard gate to every qubit in the circuit.

Applies a Hadamard gate to every qubit in the given list or range. See Qx.Patterns.h_all/2.

Creates a histogram from a raw probability tensor.

Applies an iSWAP gate, exchanging qubit states while applying an i phase factor to the swapped components.

Adds a measurement operation to the circuit.

Measures every qubit into its same-index classical bit.

Measures every qubit in the given list or range into its same-index classical bit. See Qx.Patterns.measure_all/2.

Performs a Z-basis (computational) measurement. Alias of measure/3 for symmetry with measure_x/3 and measure_y/3. See Qx.Operations.measure_z/3.

Applies a phase gate with specified phase.

Executes the quantum circuit and returns simulation results.

Applies a rotation around the X-axis.

Applies a rotation around the Y-axis.

Applies a rotation around the Z-axis.

Applies an S gate (phase gate with π/2 phase).

Applies an S† (S-dagger) gate (-π/2 phase on |1⟩).

Creates an n-qubit equal-superposition circuit (Hadamard on every qubit). Default is 1 qubit. See Qx.Patterns.superposition_circuit/1.

Applies a SWAP gate, exchanging the quantum states of two qubits.

Applies a T gate (phase gate with π/4 phase).

Inspects the circuit without breaking the pipeline.

Inspects measurement probabilities without breaking the pipeline.

Inspects the current quantum state without breaking the pipeline.

Applies the general single-qubit unitary gate U(θ,φ,λ).

Returns version information for the Qx library.

Applies a Pauli-X gate (bit flip) to the specified qubit.

Applies a Pauli-X gate to every qubit in the circuit.

Applies a Pauli-X gate to every qubit in the given list or range. See Qx.Patterns.x_all/2.

Applies a Pauli-Y gate to the specified qubit.

Applies a Pauli-Y gate to every qubit in the circuit.

Applies a Pauli-Y gate to every qubit in the given list or range. See Qx.Patterns.y_all/2.

Applies a Pauli-Z gate (phase flip) to the specified qubit.

Applies a Pauli-Z gate to every qubit in the circuit.

Applies a Pauli-Z gate to every qubit in the given list or range. See Qx.Patterns.z_all/2.

Types

bell_state_type()

@type bell_state_type() :: Qx.Patterns.bell_state_type()

circuit()

@type circuit() :: Qx.QuantumCircuit.t()

simulation_result()

@type simulation_result() :: Qx.Simulation.simulation_result()

Functions

barrier_all(circuit)

@spec barrier_all(circuit()) :: circuit()

Adds a single barrier instruction spanning every qubit.

Examples

iex> qc = Qx.create_circuit(3) |> Qx.barrier_all()
iex> Qx.QuantumCircuit.get_instructions(qc)
[{:barrier, [0, 1, 2], []}]

barrier_all(circuit, qubits)

@spec barrier_all(circuit(), Qx.Patterns.qubits()) :: circuit()

Adds a single barrier spanning the given list or range of qubits. See Qx.Patterns.barrier_all/2. Empty list/range is a no-op.

bell_state(which \\ :phi_plus)

@spec bell_state(bell_state_type()) :: circuit()

Creates one of the four Bell-state circuits (maximally entangled two-qubit states). See Qx.Patterns.bell_state_circuit/1.

AtomState
:phi_plus`Φ+⟩ = (00⟩ +11⟩)/√2` (default)
:phi_minus`Φ-⟩ = (00⟩ -11⟩)/√2`
:psi_plus`Ψ+⟩ = (01⟩ +10⟩)/√2`
:psi_minus`Ψ-⟩ = (01⟩ -10⟩)/√2`

Examples

iex> bell_circuit = Qx.bell_state()
iex> bell_circuit.num_qubits
2

iex> bell_circuit = Qx.bell_state(:psi_minus)
iex> bell_circuit.num_qubits
2

See Also

c_if(circuit, classical_bit, value, gate_fn)

@spec c_if(circuit(), non_neg_integer(), 0 | 1, (circuit() -> circuit())) :: circuit()

Applies gates conditionally based on a classical bit value.

Enables mid-circuit measurement with classical feedback - a key capability for quantum error correction, quantum teleportation, and adaptive algorithms.

Parameters

  • circuit - Quantum circuit
  • classical_bit - Classical bit index to check (must have been measured)
  • value - Value to compare (0 or 1)
  • gate_fn - Function that applies gates when condition is true

Examples

# Apply X gate to qubit 1 if classical bit 0 equals 1
iex> qc = Qx.create_circuit(2, 2)
...> |> Qx.h(0)
...> |> Qx.measure(0, 0)
...> |> Qx.c_if(0, 1, fn c -> Qx.x(c, 1) end)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
3

# Multiple gates in conditional block
iex> qc = Qx.create_circuit(3, 2)
...> |> Qx.measure(0, 0)
...> |> Qx.c_if(0, 1, fn c ->
...>      c |> Qx.x(1) |> Qx.h(2)
...>    end)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
2

See Also

  • OpenQASM 3.0 if-statements for hardware compatibility
  • Quantum teleportation example in documentation

ccx(circuit, control1, control2, target)

Applies a controlled-controlled-X (CCNOT/Toffoli) gate.

Flips target qubit if and only if both control qubits are |1⟩

Parameters

  • circuit - Quantum circuit
  • control1 - First control qubit index
  • control2 - Second control qubit index
  • target - Target qubit index

Examples

iex> qc = Qx.create_circuit(3) |> Qx.ccx(0, 1, 2)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

cp(circuit, control_qubit, target_qubit, theta)

Applies a controlled-phase (CP) gate.

Applies a phase of e^(i*theta) to the |11⟩ basis state only. All other basis states are unchanged.

Parameters

  • circuit - Quantum circuit
  • control_qubit - Control qubit index
  • target_qubit - Target qubit index
  • theta - Phase angle in radians

Examples

iex> qc = Qx.create_circuit(2) |> Qx.cp(0, 1, :math.pi())
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

Raises

create_circuit(num_qubits)

@spec create_circuit(pos_integer()) :: circuit()

Creates a new quantum circuit with only qubits (no classical bits).

Parameters

  • num_qubits - Number of qubits (1-20 recommended)

Examples

iex> qc = Qx.create_circuit(3)
iex> qc.num_qubits
3
iex> qc.num_classical_bits
0

Raises

create_circuit(num_qubits, num_classical_bits)

@spec create_circuit(pos_integer(), non_neg_integer()) :: circuit()

Creates a new quantum circuit with specified qubits and classical bits.

Parameters

  • num_qubits - Number of qubits (1-20 recommended)
  • num_classical_bits - Number of classical bits for measurements

Examples

iex> qc = Qx.create_circuit(2, 2)
iex> qc.num_qubits
2
iex> qc.num_classical_bits
2

Raises

crx(circuit, control_qubit, target_qubit, theta)

Applies a controlled rotation about the X-axis. See Qx.Operations.crx/4.

Examples

iex> qc = Qx.create_circuit(2) |> Qx.crx(0, 1, :math.pi() / 2)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

Raises

cry(circuit, control_qubit, target_qubit, theta)

Applies a controlled rotation about the Y-axis. See Qx.Operations.cry/4.

Examples

iex> qc = Qx.create_circuit(2) |> Qx.cry(0, 1, :math.pi() / 2)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

Raises

crz(circuit, control_qubit, target_qubit, theta)

Applies a controlled rotation about the Z-axis. See Qx.Operations.crz/4.

Examples

iex> qc = Qx.create_circuit(2) |> Qx.crz(0, 1, :math.pi() / 2)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

Raises

cswap(circuit, control, target_a, target_b)

Applies a Fredkin (controlled-SWAP) gate.

Swaps the quantum states of target_a and target_b when the control qubit is |1⟩. When the control qubit is |0⟩, the targets are unchanged.

Parameters

  • circuit - Quantum circuit
  • control - Control qubit index (0-based)
  • target_a - First target qubit index (0-based)
  • target_b - Second target qubit index (0-based)

Examples

iex> qc = Qx.create_circuit(3) |> Qx.cswap(0, 1, 2)
iex> [{:cswap, [0, 1, 2], []}] = Qx.QuantumCircuit.get_instructions(qc)
iex> :ok
:ok

Raises

cx(circuit, control_qubit, target_qubit)

Applies a controlled-X (CNOT) gate.

Flips target qubit if and only if control qubit is |1⟩

Parameters

  • circuit - Quantum circuit
  • control_qubit - Control qubit index
  • target_qubit - Target qubit index

Examples

iex> qc = Qx.create_circuit(2) |> Qx.cx(0, 1)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

Raises

cx_chain(circuit, qubits)

@spec cx_chain(circuit(), [non_neg_integer()]) :: circuit()

Applies a linear cascade of CNOTs along qubits.

For qubits = [q0, q1, …, qk], emits cx(q0, q1) → cx(q1, q2) → …. Empty and single-element lists are no-ops. See Qx.Patterns.cx_chain/2.

Examples

iex> qc = Qx.create_circuit(3) |> Qx.h(0) |> Qx.cx_chain([0, 1, 2])
iex> length(Qx.QuantumCircuit.get_instructions(qc))
3

Raises

cy(circuit, control_qubit, target_qubit)

Applies a controlled-Y (CY) gate. See Qx.Operations.cy/3.

Examples

iex> qc = Qx.create_circuit(2) |> Qx.cy(0, 1)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

Raises

cz(circuit, control_qubit, target_qubit)

Applies a controlled-Z (CZ) gate.

Applies a Z gate to the target qubit if and only if the control qubit is |1⟩. This is a symmetric two-qubit gate that applies a phase flip when both qubits are |1⟩.

Parameters

  • circuit - Quantum circuit
  • control_qubit - Control qubit index
  • target_qubit - Target qubit index

Examples

iex> qc = Qx.create_circuit(2) |> Qx.cz(0, 1)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

draw(result, options \\ [])

@spec draw(
  simulation_result(),
  keyword()
) :: VegaLite.t() | String.t()

Visualizes probability distribution from simulation results.

Convenience function for quickly plotting the probability distribution from a simulation result. The probabilities are automatically extracted from the result map.

For plotting raw probability tensors (e.g., from get_probabilities/1), use histogram/2 instead.

Parameters

  • result - Simulation result from run/1 or run/2
  • options - Optional plotting parameters

Options

  • :format - :vega_lite (default) or :svg
  • :title - Plot title
  • :width - Plot width (default: 400)
  • :height - Plot height (default: 300)

Examples

iex> qc = Qx.create_circuit(2) |> Qx.h(0) |> Qx.cx(0, 1)
iex> result = Qx.run(qc)
iex> plot = Qx.draw(result)
iex> is_map(plot) or is_binary(plot)
true

See Also

draw_bloch(qubit, options \\ [])

@spec draw_bloch(
  Nx.Tensor.t(),
  keyword()
) :: VegaLite.t() | String.t()

Visualizes a single qubit state on the Bloch sphere.

The Bloch sphere provides a geometric representation of a pure qubit state. This visualization is particularly useful for understanding single-qubit gates and state transformations in calculation mode.

Parameters

  • qubit - Single qubit state tensor (from Qx.Qubit)
  • options - Optional plotting parameters

Options

  • :format - :vega_lite (default) or :svg
  • :title - Plot title (default: "Bloch Sphere")
  • :size - Sphere size (default: 400)

Examples

# Visualize |0⟩ state
iex> q = Qx.Qubit.new()
iex> plot = Qx.draw_bloch(q)
iex> is_map(plot) or is_binary(plot)
true

# Visualize superposition state
iex> q = Qx.Qubit.new() |> Qx.Qubit.h()
iex> plot = Qx.draw_bloch(q, title: "Superposition State")
iex> is_map(plot) or is_binary(plot)
true

See Also

draw_counts(result, options \\ [])

@spec draw_counts(
  simulation_result(),
  keyword()
) :: VegaLite.t() | String.t()

Visualizes measurement counts as a bar chart.

Parameters

  • result - Simulation result containing measurement data
  • options - Optional plotting parameters

Examples

iex> qc = Qx.create_circuit(2, 2) |> Qx.h(0) |> Qx.measure(0, 0)
iex> result = Qx.run(qc)
iex> plot = Qx.draw_counts(result)
iex> is_map(plot) or is_binary(plot)
true

draw_state(register_or_state, options \\ [])

@spec draw_state(
  Qx.Register.t() | Nx.Tensor.t(),
  keyword()
) :: String.t()

Displays a quantum state as a formatted table.

Shows basis states with their amplitudes and probabilities. Useful for inspecting multi-qubit states in calculation mode.

Parameters

  • register_or_state - Qx.Register.t() or state tensor
  • options - Optional display parameters

Options

  • :format - :text (default) or :html
  • :precision - Decimal places (default: 3)
  • :hide_zeros - Hide zero-amplitude states (default: false)

Examples

# Display Bell state
iex> reg = Qx.Register.new(2) |> Qx.Register.h(0) |> Qx.Register.cx(0, 1)
iex> table = Qx.draw_state(reg)
iex> is_binary(table)
true

# Hide zero states
iex> reg = Qx.Register.new(3) |> Qx.Register.h(0)
iex> table = Qx.draw_state(reg, hide_zeros: true)
iex> is_binary(table)
true

See Also

get_probabilities(circuit, options \\ [])

@spec get_probabilities(
  circuit(),
  keyword()
) :: Nx.Tensor.t()

Gets probability distribution for computational basis states.

Parameters

  • circuit - Quantum circuit
  • options - Optional parameters

Options

  • :backend - Nx backend to use (e.g., {EXLA.Backend, client: :host})

Examples

iex> qc = Qx.create_circuit(1) |> Qx.h(0)
iex> probs = Qx.get_probabilities(qc)
iex> Nx.shape(probs)
{2}

# Specify backend at runtime
# Qx.get_probabilities(qc, backend: {EXLA.Backend, client: :host})

Raises

get_state(circuit, options \\ [])

@spec get_state(
  circuit(),
  keyword()
) :: Nx.Tensor.t()

Executes a circuit and returns only the final quantum state.

Parameters

  • circuit - Quantum circuit to execute
  • options - Optional parameters

Options

  • :backend - Nx backend to use (e.g., {EXLA.Backend, client: :host})

Examples

iex> qc = Qx.create_circuit(1) |> Qx.h(0)
iex> state = Qx.get_state(qc)
iex> Nx.shape(state)
{2}

# Specify backend at runtime
# Qx.get_state(qc, backend: {EXLA.Backend, client: :host})

Raises

ghz_state(num_qubits \\ 3)

@spec ghz_state(pos_integer()) :: circuit()

Creates an n-qubit GHZ-state preparation circuit. Default is 3 qubits.

Returns a circuit that prepares |GHZ⟩ = (|0…0⟩ + |1…1⟩)/√2 on a |0…0⟩ input. See Qx.Patterns.ghz_state_circuit/1.

Examples

iex> ghz_circuit = Qx.ghz_state()
iex> ghz_circuit.num_qubits
3

iex> ghz_circuit = Qx.ghz_state(5)
iex> ghz_circuit.num_qubits
5

See Also

h(circuit, qubit)

@spec h(circuit(), non_neg_integer()) :: circuit()

Applies a Hadamard gate to the specified qubit.

Creates superposition: |0⟩ → (|0⟩ + |1⟩)/√2, |1⟩ → (|0⟩ - |1⟩)/√2

Parameters

  • circuit - Quantum circuit
  • qubit - Target qubit index

Examples

iex> qc = Qx.create_circuit(1) |> Qx.h(0)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

Raises

h_all(circuit)

@spec h_all(circuit()) :: circuit()

Applies a Hadamard gate to every qubit in the circuit.

Convenience for the recurring Enum.reduce(0..(n - 1), qc, &Qx.h(&2, &1)) motif (Grover diffuser, Bernstein-Vazirani oracle, equal-superposition preparation). See Qx.Patterns for the full set of composite patterns.

Examples

iex> qc = Qx.create_circuit(3) |> Qx.h_all()
iex> length(Qx.QuantumCircuit.get_instructions(qc))
3

h_all(circuit, qubits)

@spec h_all(circuit(), Qx.Patterns.qubits()) :: circuit()

Applies a Hadamard gate to every qubit in the given list or range. See Qx.Patterns.h_all/2.

Examples

iex> qc = Qx.create_circuit(5) |> Qx.h_all(0..2)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
3

histogram(probabilities, options \\ [])

@spec histogram(
  Nx.Tensor.t(),
  keyword()
) :: VegaLite.t() | String.t()

Creates a histogram from a raw probability tensor.

Use this function when you have a probability tensor and want to visualize it. This is useful for:

  • Plotting probabilities from get_probabilities/1 without running simulation
  • Visualizing custom or theoretical probability distributions
  • Comparing different probability distributions

For quick visualization of simulation results, use draw/2 instead.

Parameters

  • probabilities - Nx tensor of probabilities (should sum to 1.0)
  • options - Optional plotting parameters

Examples

# Visualize probabilities without full simulation
iex> qc = Qx.create_circuit(2) |> Qx.h(0)
iex> probs = Qx.get_probabilities(qc)
iex> hist = Qx.histogram(probs)
iex> is_map(hist) or is_binary(hist)
true

See Also

iswap(circuit, qubit_a, qubit_b)

@spec iswap(circuit(), non_neg_integer(), non_neg_integer()) :: circuit()

Applies an iSWAP gate, exchanging qubit states while applying an i phase factor to the swapped components.

Native to superconducting qubit hardware (Google Sycamore, Rigetti). Unlike SWAP, applying iSWAP twice is not the identity — it produces a -1 phase.

Parameters

  • circuit - Quantum circuit
  • qubit_a - Index of the first qubit
  • qubit_b - Index of the second qubit

Examples

iex> qc = Qx.create_circuit(2) |> Qx.iswap(0, 1)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

Raises

measure(circuit, qubit, classical_bit)

@spec measure(circuit(), non_neg_integer(), non_neg_integer()) :: circuit()

Adds a measurement operation to the circuit.

Parameters

  • circuit - Quantum circuit
  • qubit - Qubit index to measure
  • classical_bit - Classical bit index to store result

Examples

iex> qc = Qx.create_circuit(2, 2) |> Qx.measure(0, 0)
iex> length(Qx.QuantumCircuit.get_measurements(qc))
1

Raises

measure_all(circuit)

@spec measure_all(circuit()) :: circuit()

Measures every qubit into its same-index classical bit.

Raises Qx.ClassicalBitError if circuit.num_classical_bits < num_qubits — the caller owns the circuit shape (see Qx.Patterns.measure_all/1).

Examples

iex> qc = Qx.create_circuit(3, 3) |> Qx.measure_all()
iex> length(Qx.QuantumCircuit.get_measurements(qc))
3

Raises

measure_all(circuit, qubits)

@spec measure_all(circuit(), Qx.Patterns.qubits()) :: circuit()

Measures every qubit in the given list or range into its same-index classical bit. See Qx.Patterns.measure_all/2.

Raises

measure_x(circuit, qubit, classical_bit)

@spec measure_x(circuit(), non_neg_integer(), non_neg_integer()) :: circuit()

Performs an X-basis measurement. See Qx.Operations.measure_x/3.

Examples

iex> qc = Qx.create_circuit(1, 1) |> Qx.measure_x(0, 0)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
2

Raises

measure_y(circuit, qubit, classical_bit)

@spec measure_y(circuit(), non_neg_integer(), non_neg_integer()) :: circuit()

Performs a Y-basis measurement. See Qx.Operations.measure_y/3.

Examples

iex> qc = Qx.create_circuit(1, 1) |> Qx.measure_y(0, 0)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
3

Raises

measure_z(circuit, qubit, classical_bit)

@spec measure_z(circuit(), non_neg_integer(), non_neg_integer()) :: circuit()

Performs a Z-basis (computational) measurement. Alias of measure/3 for symmetry with measure_x/3 and measure_y/3. See Qx.Operations.measure_z/3.

Examples

iex> qc = Qx.create_circuit(1, 1) |> Qx.measure_z(0, 0)
iex> length(Qx.QuantumCircuit.get_measurements(qc))
1

phase(circuit, qubit, phi)

@spec phase(circuit(), non_neg_integer(), float()) :: circuit()

Applies a phase gate with specified phase.

Parameters

  • circuit - Quantum circuit
  • qubit - Target qubit index
  • phi - Phase angle in radians

Examples

iex> qc = Qx.create_circuit(1) |> Qx.phase(0, :math.pi/4)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

run(circuit, options \\ [])

@spec run(circuit(), pos_integer() | keyword()) :: simulation_result()

Executes the quantum circuit and returns simulation results.

Parameters

  • circuit - Quantum circuit to execute
  • options - Optional parameters (can be keyword list or integer for backward compatibility)

Options

  • :shots - Number of measurement shots (default: 1024)
  • :backend - Nx backend to use (e.g., {EXLA.Backend, client: :host})
  • :renormalize - Counter unitary float drift (default: false). false = off; true = renormalize at measurement-time; positive integer N = renormalize every N gates and at measurement-time. Other values raise Qx.OptionError. See Qx.Simulation.run/2 for the float32 accuracy note.

Returns

A map containing:

  • :probabilities - Probability amplitudes for all states
  • :classical_bits - List of measurement results
  • :state - Final quantum state vector
  • :shots - Number of shots performed
  • :counts - Frequency count of measurement outcomes

Examples

iex> qc = Qx.create_circuit(1) |> Qx.h(0)
iex> result = Qx.run(qc)
iex> is_map(result)
true
iex> Map.has_key?(result, :probabilities)
true

# Specify backend at runtime
# Qx.run(qc, backend: {EXLA.Backend, client: :host})

# Backward compatible: pass shots as integer
# Qx.run(qc, 2048)

rx(circuit, qubit, theta)

@spec rx(circuit(), non_neg_integer(), float()) :: circuit()

Applies a rotation around the X-axis.

Parameters

  • circuit - Quantum circuit
  • qubit - Target qubit index
  • theta - Rotation angle in radians

Examples

iex> qc = Qx.create_circuit(1) |> Qx.rx(0, :math.pi/2)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

ry(circuit, qubit, theta)

@spec ry(circuit(), non_neg_integer(), float()) :: circuit()

Applies a rotation around the Y-axis.

Parameters

  • circuit - Quantum circuit
  • qubit - Target qubit index
  • theta - Rotation angle in radians

Examples

iex> qc = Qx.create_circuit(1) |> Qx.ry(0, :math.pi/2)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

rz(circuit, qubit, theta)

@spec rz(circuit(), non_neg_integer(), float()) :: circuit()

Applies a rotation around the Z-axis.

Parameters

  • circuit - Quantum circuit
  • qubit - Target qubit index
  • theta - Rotation angle in radians

Examples

iex> qc = Qx.create_circuit(1) |> Qx.rz(0, :math.pi/2)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

s(circuit, qubit)

@spec s(circuit(), non_neg_integer()) :: circuit()

Applies an S gate (phase gate with π/2 phase).

Parameters

  • circuit - Quantum circuit
  • qubit - Target qubit index

Examples

iex> qc = Qx.create_circuit(1) |> Qx.s(0)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

sdg(circuit, qubit)

@spec sdg(circuit(), non_neg_integer()) :: circuit()

Applies an S† (S-dagger) gate (-π/2 phase on |1⟩).

Rotates the Y-basis back to the X-basis. The inverse of s/2.

Parameters

  • circuit - Quantum circuit
  • qubit - Target qubit index

Examples

iex> qc = Qx.create_circuit(1) |> Qx.sdg(0)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

superposition(num_qubits \\ 1)

@spec superposition(pos_integer()) :: circuit()

Creates an n-qubit equal-superposition circuit (Hadamard on every qubit). Default is 1 qubit. See Qx.Patterns.superposition_circuit/1.

Examples

iex> sup_circuit = Qx.superposition()
iex> sup_circuit.num_qubits
1

iex> sup_circuit = Qx.superposition(3)
iex> length(Qx.QuantumCircuit.get_instructions(sup_circuit))
3

swap(circuit, qubit_a, qubit_b)

@spec swap(circuit(), non_neg_integer(), non_neg_integer()) :: circuit()

Applies a SWAP gate, exchanging the quantum states of two qubits.

Both qubits are treated symmetrically — there is no control/target distinction.

Parameters

  • circuit - Quantum circuit
  • qubit_a - Index of the first qubit
  • qubit_b - Index of the second qubit

Examples

iex> qc = Qx.create_circuit(2) |> Qx.swap(0, 1)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

Raises

t(circuit, qubit)

@spec t(circuit(), non_neg_integer()) :: circuit()

Applies a T gate (phase gate with π/4 phase).

Parameters

  • circuit - Quantum circuit
  • qubit - Target qubit index

Examples

iex> qc = Qx.create_circuit(1) |> Qx.t(0)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

tap_circuit(circuit, fun)

@spec tap_circuit(circuit(), (circuit() -> any())) :: circuit()

Inspects the circuit without breaking the pipeline.

See Qx.Operations.tap_circuit/2 for full documentation.

Examples

# Inspect instructions while building circuit
circuit = Qx.create_circuit(2)
  |> Qx.h(0)
  |> Qx.tap_circuit(fn c -> IO.puts("Gates: #{length(c.instructions)}") end)
  |> Qx.cx(0, 1)

tap_probabilities(circuit, fun)

@spec tap_probabilities(circuit(), (Nx.Tensor.t() -> any())) :: circuit()

Inspects measurement probabilities without breaking the pipeline.

See Qx.Operations.tap_probabilities/2 for full documentation.

Examples

# Inspect probabilities while building circuit
circuit = Qx.create_circuit(2)
  |> Qx.h(0)
  |> Qx.tap_probabilities(fn p -> IO.puts("Probs: #{inspect(Nx.shape(p))}") end)
  |> Qx.cx(0, 1)

tap_state(circuit, fun)

@spec tap_state(circuit(), (Nx.Tensor.t() -> any())) :: circuit()

Inspects the current quantum state without breaking the pipeline.

See Qx.Operations.tap_state/2 for full documentation.

Examples

# Inspect quantum state while building circuit
circuit = Qx.create_circuit(1)
  |> Qx.h(0)
  |> Qx.tap_state(fn s -> IO.puts("State shape: #{inspect(Nx.shape(s))}") end)
  |> Qx.z(0)

u(circuit, qubit, theta, phi, lambda)

@spec u(circuit(), non_neg_integer(), number(), number(), number()) :: circuit()

Applies the general single-qubit unitary gate U(θ,φ,λ).

U(θ,φ,λ) = [[cos(θ/2), -e^(iλ)·sin(θ/2) ],

         [e^()·sin(θ/2),  e^(i(φ+λ))·cos(θ/2) ]]

Follows the OpenQASM 3.0 specification built-in U gate / Qiskit qiskit.circuit.library.UGate convention.

Decomposition identity: U(θ,φ,λ) = RZ(φ)·RY(θ)·RZ(λ) up to the global phase e^{i(φ+λ)/2}. For the X/H/I/Y special cases the result is exact — Qiskit's UGate carries no extra global phase.

Parameters

  • circuit - Quantum circuit
  • qubit - Target qubit index (0-based)
  • theta (θ) - Polar rotation angle in radians
  • phi (φ) - Phase angle in radians
  • lambda (λ) - Phase angle in radians

Examples

iex> qc = Qx.create_circuit(1) |> Qx.u(0, :math.pi(), 0, :math.pi())
iex> [{:u, [0], params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> length(params)
3

Raises

version()

@spec version() :: String.t()

Returns version information for the Qx library.

Examples

iex> version = Qx.version()
iex> is_binary(version)
true

x(circuit, qubit)

@spec x(circuit(), non_neg_integer()) :: circuit()

Applies a Pauli-X gate (bit flip) to the specified qubit.

Flips |0⟩ ↔ |1⟩

Parameters

  • circuit - Quantum circuit
  • qubit - Target qubit index

Examples

iex> qc = Qx.create_circuit(1) |> Qx.x(0)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

Raises

x_all(circuit)

@spec x_all(circuit()) :: circuit()

Applies a Pauli-X gate to every qubit in the circuit.

Examples

iex> qc = Qx.create_circuit(2) |> Qx.x_all()
iex> length(Qx.QuantumCircuit.get_instructions(qc))
2

x_all(circuit, qubits)

@spec x_all(circuit(), Qx.Patterns.qubits()) :: circuit()

Applies a Pauli-X gate to every qubit in the given list or range. See Qx.Patterns.x_all/2.

y(circuit, qubit)

@spec y(circuit(), non_neg_integer()) :: circuit()

Applies a Pauli-Y gate to the specified qubit.

Combines bit flip and phase flip transformations.

Parameters

  • circuit - Quantum circuit
  • qubit - Target qubit index

Examples

iex> qc = Qx.create_circuit(1) |> Qx.y(0)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

Raises

y_all(circuit)

@spec y_all(circuit()) :: circuit()

Applies a Pauli-Y gate to every qubit in the circuit.

Examples

iex> qc = Qx.create_circuit(2) |> Qx.y_all()
iex> length(Qx.QuantumCircuit.get_instructions(qc))
2

y_all(circuit, qubits)

@spec y_all(circuit(), Qx.Patterns.qubits()) :: circuit()

Applies a Pauli-Y gate to every qubit in the given list or range. See Qx.Patterns.y_all/2.

z(circuit, qubit)

@spec z(circuit(), non_neg_integer()) :: circuit()

Applies a Pauli-Z gate (phase flip) to the specified qubit.

Leaves |0⟩ unchanged, applies -1 phase to |1⟩

Parameters

  • circuit - Quantum circuit
  • qubit - Target qubit index

Examples

iex> qc = Qx.create_circuit(1) |> Qx.z(0)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
1

Raises

z_all(circuit)

@spec z_all(circuit()) :: circuit()

Applies a Pauli-Z gate to every qubit in the circuit.

Examples

iex> qc = Qx.create_circuit(2) |> Qx.z_all()
iex> length(Qx.QuantumCircuit.get_instructions(qc))
2

z_all(circuit, qubits)

@spec z_all(circuit(), Qx.Patterns.qubits()) :: circuit()

Applies a Pauli-Z gate to every qubit in the given list or range. See Qx.Patterns.z_all/2.