Source code for qarp.blocks._state_preparation.ghz_like_state_block
from typing import List, Optional
import numpy as np
from .._block import SimpleBlock
from .._prepares_known_state import prepares_known_state
[docs]
@prepares_known_state
class GHZLikeStateBlock(SimpleBlock):
def __init__(
self,
basis_state: List[int],
dephase: bool = False,
target_qubits: Optional[List[int]] = None,
name=None,
):
"""GHZ-like state preparation with optional dephasing.
GHZLikeStateBlock prepares a multi-qubit entangled state resembling a GHZ state but
localized to specific basis states. It creates entanglement by applying a Hadamard
gate to the first qubit marked as |1⟩ in the basis state, then cascading CNOT gates
to entangle subsequent |1⟩-marked qubits. An optional S† gate provides phase control,
enabling preparation of states like (|000...⟩ - i|111...⟩)/√2 useful for quantum
algorithms requiring controlled superposition with specific phase relationships.
Args:
basis_state: A list of 0s and 1s representing which qubits participate in the GHZ-like state.
dephase: If True, applies S† gate to introduce phase factor i in the superposition.
target_qubits: The target qubits this block acts on when added to a larger circuit.
name: Optional custom name for the block. If None, auto-generated from basis_state and dephase.
"""
self.basis_state = basis_state
if name is None:
s = [str(int(i)) for i in self.basis_state]
state_string = "".join(s)
if not dephase:
name = f"GHZ(+, {state_string})"
else:
name = f"GHZ(i, {state_string})"
super().__init__(
len(self.basis_state),
target_qubits=target_qubits,
name=name,
)
self.dephase = dephase
[docs]
def build_vanilla(self):
"""
Build a GHZ-like state by applying H on the first qubit with basis_state=1,
then cascading CNOTs from that qubit to all other qubits with basis_state=1.
"""
ones_indices = [idx for idx, bit in enumerate(self.basis_state) if bit == 1]
if ones_indices:
first_one_idx = ones_indices[0]
self.h(first_one_idx)
if self.dephase:
self.sdg(first_one_idx)
for i in range(len(ones_indices) - 1):
self.cx(ones_indices[i], ones_indices[i + 1])
[docs]
def target_statevector(self) -> np.ndarray:
r"""``(|0…0⟩ + p·|mask⟩)/√2``, with ``p = -i`` when dephasing.
``Sdg = diag(1, -i)`` (§2.2) follows the Hadamard, so the marked branch
picks up ``-i``, not ``+i``. An empty mask leaves ``|0…0⟩`` unentangled.
"""
psi = np.zeros(2**self.n_qubits, dtype=complex)
mask = sum(1 << i for i, bit in enumerate(self.basis_state) if bit == 1)
if mask == 0:
psi[0] = 1.0
return psi
psi[0] = 1 / np.sqrt(2)
psi[mask] = (-1j if self.dephase else 1.0) / np.sqrt(2)
return psi