Source code for uniqc.algorithmics.circuits.entangled_states

"""Entangled state preparation circuits: GHZ, W, and Cluster states."""

__all__ = [
    "ghz_state",
    "w_state",
    "cluster_state",
]

from typing import List, Optional, Tuple

from uniqc.circuit_builder import Circuit
from uniqc.algorithmics.circuits.dicke_state import dicke_state_circuit


[docs] def ghz_state( circuit: Circuit, qubits: Optional[List[int]] = None, ) -> None: r"""Prepare a GHZ (Greenberger–Horne–Zeilinger) state. Produces the state: .. math:: \frac{1}{\sqrt{2}}(|00\ldots0\rangle + |11\ldots1\rangle) Implementation: 1. Hadamard on the first qubit: :math:`\frac{1}{\sqrt{2}}(|0\rangle + |1\rangle)` 2. Chain of CNOT gates: ``CNOT(q[0], q[1])``, ``CNOT(q[1], q[2])``, ... Args: circuit: Quantum circuit to operate on (mutated in-place). qubits: Qubit indices. ``None`` means all qubits of *circuit*. Raises: ValueError: Fewer than 2 qubits. Example: >>> from uniqc.circuit_builder import Circuit >>> from uniqc.algorithmics.circuits import ghz_state >>> c = Circuit(3) >>> ghz_state(c) """ if qubits is None: qubits = list(range(circuit.qubit_num)) n = len(qubits) if n < 2: raise ValueError("ghz_state requires at least 2 qubits") circuit.h(qubits[0]) for i in range(n - 1): circuit.cnot(qubits[i], qubits[i + 1])
[docs] def w_state( circuit: Circuit, qubits: Optional[List[int]] = None, ) -> None: r"""Prepare a W state. Produces the state: .. math:: \frac{1}{\sqrt{n}}(|10\ldots0\rangle + |01\ldots0\rangle + \ldots + |00\ldots1\rangle) Implemented as a Dicke state :math:`|D(n,1)\rangle` (equal superposition of all single-excitation computational basis states) via :func:`dicke_state_circuit` with ``k=1``. Args: circuit: Quantum circuit to operate on (mutated in-place). qubits: Qubit indices. ``None`` means all qubits of *circuit*. Raises: ValueError: Fewer than 2 qubits. Example: >>> from uniqc.circuit_builder import Circuit >>> from uniqc.algorithmics.circuits import w_state >>> c = Circuit(4) >>> w_state(c) """ if qubits is None: qubits = list(range(circuit.qubit_num)) if len(qubits) < 2: raise ValueError("w_state requires at least 2 qubits") dicke_state_circuit(circuit, k=1, qubits=qubits)
[docs] def cluster_state( circuit: Circuit, qubits: Optional[List[int]] = None, edges: Optional[List[Tuple[int, int]]] = None, ) -> None: r"""Prepare a cluster state (graph state). A cluster state is prepared by: 1. Applying Hadamard to all qubits: :math:`H^{\otimes n}` 2. Applying CZ (controlled-Z) on each edge of the graph The resulting state is: .. math:: \frac{1}{\sqrt{2^n}} \sum_{x \in \{0,1\}^n} (-1)^{\sum_{(i,j) \in E} x_i x_j} |x\rangle Args: circuit: Quantum circuit to operate on (mutated in-place). qubits: Qubit indices. ``None`` means all qubits of *circuit*. edges: List of (source, target) pairs defining the entanglement graph. Indices refer to positions in *qubits*. ``None`` uses a linear nearest-neighbor chain: ``(0,1), (1,2), (2,3), ...``. Raises: ValueError: Fewer than 1 qubit. Example: >>> from uniqc.circuit_builder import Circuit >>> from uniqc.algorithmics.circuits import cluster_state >>> c = Circuit(4) >>> cluster_state(c) # linear chain >>> # Custom graph (square) >>> c2 = Circuit(4) >>> cluster_state(c2, edges=[(0,1), (1,2), (2,3), (3,0)]) """ if qubits is None: qubits = list(range(circuit.qubit_num)) n = len(qubits) if n < 1: raise ValueError("cluster_state requires at least 1 qubit") # Step 1: Hadamard on all qubits for q in qubits: circuit.h(q) # Step 2: CZ on each edge if edges is None: # Linear chain edges = [(i, i + 1) for i in range(n - 1)] for src_idx, tgt_idx in edges: if src_idx >= n or tgt_idx >= n: raise ValueError( f"Edge ({src_idx}, {tgt_idx}) out of range for {n} qubits" ) circuit.cz(qubits[src_idx], qubits[tgt_idx])