Qx.Patterns (Qx - Quantum Computing Simulator v0.8.0)

View Source

Composite circuit-building patterns: thin wrappers that emit multiple instructions in one call.

Where Qx.Operations emits exactly one instruction per call (one gate, one qubit), this module bundles the recurring "apply X to every qubit" / "measure every qubit" / "CNOT chain" motifs that appear in tutorials and algorithm circuits (Grover diffuser, Bernstein-Vazirani oracle, GHZ preparation, etc.).

All helpers are additive over Qx.Operations and Qx.QuantumCircuit; they introduce no new exception types. Out-of-range qubit indices or insufficient classical bits surface the existing typed errors (Qx.QubitIndexError, Qx.ClassicalBitError) from the underlying primitives.

Each _all helper has two arities:

  • /1 — apply to every qubit in the circuit (whole-circuit form).
  • /2 — apply to a sub-list or range of qubits (sub-register form), e.g. Qx.Patterns.h_all(qc, 0..2) or Qx.Patterns.h_all(qc, [0, 2, 4]).

See also:

  • Qx.Operations — one-instruction-per-call gate API.
  • Qx.StateInit — sibling module for composite state-vector recipes (Bell state, GHZ state, W state). Qx.Patterns is the circuit-instruction analogue.

Examples

# Equal superposition over all qubits (replaces a private `apply_h_all`
# helper used in tutorials).
iex> qc = Qx.create_circuit(3) |> Qx.Patterns.h_all()
iex> length(Qx.QuantumCircuit.get_instructions(qc))
3

# Equal superposition over a sub-register.
iex> qc = Qx.create_circuit(5) |> Qx.Patterns.h_all(0..2)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
3

# Measure every qubit into its same-index classical bit.
iex> qc = Qx.create_circuit(2, 2) |> Qx.Patterns.measure_all()
iex> Qx.QuantumCircuit.get_instructions(qc)
[{:measure, [0, 0], []}, {:measure, [1, 1], []}]

# GHZ-style linear CNOT chain.
iex> qc = Qx.create_circuit(4) |> Qx.Patterns.cx_chain([0, 1, 2, 3])
iex> length(Qx.QuantumCircuit.get_instructions(qc))
3

Summary

Types

Selector for which of the four Bell states a recipe builds.

A list or range of non-negative qubit indices.

Functions

Adds a single barrier instruction spanning every qubit in circuit.

Adds a single barrier instruction spanning the given list or range of qubits.

Builds a two-qubit circuit recipe that prepares one of the four Bell states. Selector defaults to :phi_plus.

Applies a linear cascade of CNOTs along qubits.

Builds an n-qubit GHZ-state preparation circuit: H(0) followed by a linear cx_chain([0, 1, …, n-1]). Final state on |0…0⟩ input is (|0…0⟩ + |1…1⟩)/√2. Default is 3 qubits.

Applies a Hadamard gate to every qubit in circuit.

Applies a Hadamard gate to every qubit in the given list or range.

Measures every qubit into its same-index classical bit.

Measures every qubit in the given list or range into its same-index classical bit (qubit i → classical bit i).

Builds an n-qubit equal-superposition circuit: H applied to every qubit, on a |0…0⟩ input the result is the uniform superposition. Default is 1 qubit.

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

Applies a Pauli-X gate to every qubit in the given list or range.

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

Applies a Pauli-Y gate to every qubit in the given list or range.

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

Applies a Pauli-Z gate to every qubit in the given list or range.

Types

bell_state_type()

@type bell_state_type() :: :phi_plus | :phi_minus | :psi_plus | :psi_minus

Selector for which of the four Bell states a recipe builds.

qubits()

@type qubits() :: [non_neg_integer()] | Range.t()

A list or range of non-negative qubit indices.

Used as the second argument to the /2 form of h_all, x_all, y_all, z_all, measure_all, and barrier_all to select a sub-register.

Functions

barrier_all(circuit)

@spec barrier_all(Qx.QuantumCircuit.t()) :: Qx.QuantumCircuit.t()

Adds a single barrier instruction spanning every qubit in circuit.

Equivalent to Qx.Operations.barrier(circuit, Enum.to_list(0..(n - 1))).

Examples

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

barrier_all(circuit, qubits)

@spec barrier_all(Qx.QuantumCircuit.t(), qubits()) :: Qx.QuantumCircuit.t()

Adds a single barrier instruction spanning the given list or range of qubits.

An empty list or empty range is a no-op (returns circuit unchanged).

Examples

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

bell_state_circuit(which \\ :phi_plus)

@spec bell_state_circuit(bell_state_type()) :: Qx.QuantumCircuit.t()

Builds a two-qubit circuit recipe that prepares one of the four Bell states. Selector defaults to :phi_plus.

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

Examples

iex> qc = Qx.Patterns.bell_state_circuit()
iex> qc.num_qubits
2

iex> qc = Qx.Patterns.bell_state_circuit(:psi_minus)
iex> qc.num_qubits
2

See Also

cx_chain(circuit, qubits)

Applies a linear cascade of CNOTs along qubits.

For qubits = [q0, q1, q2, ..., qk], emits CNOTs cx(q0, q1), cx(q1, q2), …, cx(q_{k-1}, q_k) — i.e. each qubit controls the next. This is the shape used to build GHZ states (e.g. H(0) → cx(0,1) → cx(1,2)).

Lists of length 0 or 1 are deliberate no-ops and return circuit unchanged.

Examples

iex> qc = Qx.create_circuit(4) |> Qx.Patterns.cx_chain([0, 1, 2, 3])
iex> Qx.QuantumCircuit.get_instructions(qc)
[{:cx, [0, 1], []}, {:cx, [1, 2], []}, {:cx, [2, 3], []}]

iex> qc = Qx.create_circuit(2) |> Qx.Patterns.cx_chain([])
iex> Qx.QuantumCircuit.get_instructions(qc)
[]

iex> qc = Qx.create_circuit(2) |> Qx.Patterns.cx_chain([0])
iex> Qx.QuantumCircuit.get_instructions(qc)
[]

ghz_state_circuit(num_qubits \\ 3)

@spec ghz_state_circuit(pos_integer()) :: Qx.QuantumCircuit.t()

Builds an n-qubit GHZ-state preparation circuit: H(0) followed by a linear cx_chain([0, 1, …, n-1]). Final state on |0…0⟩ input is (|0…0⟩ + |1…1⟩)/√2. Default is 3 qubits.

Examples

iex> qc = Qx.Patterns.ghz_state_circuit()
iex> qc.num_qubits
3

iex> qc = Qx.Patterns.ghz_state_circuit(5)
iex> qc.num_qubits
5

See Also

h_all(circuit)

Applies a Hadamard gate to every qubit in circuit.

Equivalent to Enum.reduce(0..(n - 1), circuit, &Qx.h(&2, &1)) where n is circuit.num_qubits, but expresses the intent directly.

Examples

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

h_all(circuit, qubits)

Applies a Hadamard gate to every qubit in the given list or range.

Examples

iex> qc = Qx.create_circuit(5) |> Qx.Patterns.h_all([0, 2, 4])
iex> Qx.QuantumCircuit.get_instructions(qc)
[{:h, [0], []}, {:h, [2], []}, {:h, [4], []}]

iex> qc = Qx.create_circuit(5) |> Qx.Patterns.h_all(1..3)
iex> Qx.QuantumCircuit.get_instructions(qc)
[{:h, [1], []}, {:h, [2], []}, {:h, [3], []}]

measure_all(circuit)

@spec measure_all(Qx.QuantumCircuit.t()) :: Qx.QuantumCircuit.t()

Measures every qubit into its same-index classical bit.

Emits n measurement instructions where n = circuit.num_qubits, each mapping qubit i to classical bit i.

Raises Qx.ClassicalBitError if circuit.num_classical_bits < num_qubits — the circuit shape is the caller's decision (made at create_circuit/2), and no auto-grow happens.

Examples

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

measure_all(circuit, qubits)

@spec measure_all(Qx.QuantumCircuit.t(), qubits()) :: Qx.QuantumCircuit.t()

Measures every qubit in the given list or range into its same-index classical bit (qubit i → classical bit i).

Examples

iex> qc = Qx.create_circuit(3, 3) |> Qx.Patterns.measure_all([0, 2])
iex> Qx.QuantumCircuit.get_instructions(qc)
[{:measure, [0, 0], []}, {:measure, [2, 2], []}]

superposition_circuit(num_qubits \\ 1)

@spec superposition_circuit(pos_integer()) :: Qx.QuantumCircuit.t()

Builds an n-qubit equal-superposition circuit: H applied to every qubit, on a |0…0⟩ input the result is the uniform superposition. Default is 1 qubit.

Examples

iex> qc = Qx.Patterns.superposition_circuit()
iex> qc.num_qubits
1

iex> qc = Qx.Patterns.superposition_circuit(3)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
3

x_all(circuit)

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

Examples

iex> qc = Qx.create_circuit(2) |> Qx.Patterns.x_all()
iex> Qx.QuantumCircuit.get_instructions(qc)
[{:x, [0], []}, {:x, [1], []}]

x_all(circuit, qubits)

Applies a Pauli-X gate to every qubit in the given list or range.

Examples

iex> qc = Qx.create_circuit(4) |> Qx.Patterns.x_all([0, 3])
iex> Qx.QuantumCircuit.get_instructions(qc)
[{:x, [0], []}, {:x, [3], []}]

y_all(circuit)

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

Examples

iex> qc = Qx.create_circuit(2) |> Qx.Patterns.y_all()
iex> Qx.QuantumCircuit.get_instructions(qc)
[{:y, [0], []}, {:y, [1], []}]

y_all(circuit, qubits)

Applies a Pauli-Y gate to every qubit in the given list or range.

Examples

iex> qc = Qx.create_circuit(3) |> Qx.Patterns.y_all(0..1)
iex> Qx.QuantumCircuit.get_instructions(qc)
[{:y, [0], []}, {:y, [1], []}]

z_all(circuit)

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

Examples

iex> qc = Qx.create_circuit(2) |> Qx.Patterns.z_all()
iex> Qx.QuantumCircuit.get_instructions(qc)
[{:z, [0], []}, {:z, [1], []}]

z_all(circuit, qubits)

Applies a Pauli-Z gate to every qubit in the given list or range.

Examples

iex> qc = Qx.create_circuit(3) |> Qx.Patterns.z_all([2])
iex> Qx.QuantumCircuit.get_instructions(qc)
[{:z, [2], []}]