Skip to content

States (common state-preparation circuits)

A GHZ state -- (|00...0> + |11...1>) / sqrt(2), every qubit perfectly correlated with every other one -- is the standard multi-qubit entanglement benchmark: it shows up at the top of practically every experiment and test script in this package, usually hand-written as [('h', 0), ('cx', 0, 1), ('cx', 1, 2), ...]. ghz_state is that snippet, written once.

Step 1. Build and run a GHZ state

import numpy as np
import dense_evolution as de

sim = de.DenseSVSimulator(3)
sim.run_circuit(de.ghz_state(3))
print(de.ghz_state(3))
print(np.round(sim.get_probabilities(), 4))
[('h', 0), ('cx', 0, 1), ('cx', 1, 2)]
[0.5 0.  0.  0.  0.  0.  0.  0.5]

de.ghz_state(3) is a plain gate-tuple list -- H on qubit 0, then a linear chain of cx gates propagating that superposition outward one qubit at a time -- so it drops straight into run_circuit like any hand-built circuit. Only index 0 (|000>) and index 7 (|111>) carry probability, each exactly 0.5: measuring always gives all zeros or all ones, never a mix.

Step 2. What noise does to it

from dense_evolution.registry import NoiseModel

noisy_sv = NoiseModel.apply_to_sv(
    np.asarray(sim.get_statevector()), n=3, model='depolarizing', p=0.05,
    rng=np.random.default_rng(0),
)
print(np.round(np.abs(noisy_sv) ** 2, 4))
[0.   0.   0.5  0.   0.   0.5  0.   0.  ]

Depolarizing noise at p=0.05 on this particular random draw flipped one qubit, moving all the probability from |000>/|111> to |010>/|101> -- a stark, worst-case-looking result from a single 3-qubit sample, not a general "GHZ states are fragile" statement; see Noise for the full model and how averaging over many trajectories (as ZNE does) recovers a smooth error curve instead of one noisy sample like this.


Details

Requires n_qubits >= 2 -- a single qubit has no partner to entangle with, so an n=1 "GHZ state" is undefined and raises ValueError.

Implementation: [('h', 0)] + entangling_layer(n_qubits, pattern='linear', gate='cx') -- ghz_state is a thin, named wrapper around entangling_layer's 'linear' pattern, not a separate implementation. Building the same superposition-then-chain idea with a different topology (e.g. pattern='star' for a hub-and-spoke GHZ variant) means calling entangling_layer directly instead.

See also: Topology for entangling_layer and its other four connectivity patterns; QFT for the other standard textbook circuit builder in this package.

states

Common state-preparation circuits, returned as gate-tuple lists ready to feed straight into run_circuit (or to concatenate with more gates first). The GHZ-state snippet in particular -- [('h', 0), ('cx', 0, 1), ('cx', 1, 2), ...] -- shows up hand-written at the top of practically every experiment and test script built on this package; ghz_state is that snippet, written once.

ghz_state

ghz_state(n_qubits)

Build the GHZ-state preparation circuit: (|00...0> + |11...1>) / sqrt(2).

Implementation: H on qubit 0, then a linear CX chain (qubit 0 -> 1, 1 -> 2, ..., n-2 -> n-1) propagating the superposition outward -- reuses entangling_layer(n_qubits, pattern='linear') for the chain.

Parameters:

Name Type Description Default
n_qubits int

Number of qubits, must be >= 2 (a single qubit has no partner to entangle with, so an n=1 "GHZ state" is undefined here).

required

Returns:

Type Description
list[tuple]

e.g. ghz_state(3) == [('h', 0), ('cx', 0, 1), ('cx', 1, 2)]

Examples:

>>> import dense_evolution as de
>>> sim = de.DenseSVSimulator(3)
>>> sim.run_circuit(de.ghz_state(3))
>>> sim.get_probabilities()[[0, 7]]  # |000> and |111>, each 0.5
Source code in dense_evolution/physics/states.py
def ghz_state(n_qubits):
    """
    Build the GHZ-state preparation circuit:
    (|00...0> + |11...1>) / sqrt(2).

    Implementation: H on qubit 0, then a linear CX chain (qubit 0 -> 1,
    1 -> 2, ..., n-2 -> n-1) propagating the superposition outward --
    reuses `entangling_layer(n_qubits, pattern='linear')` for the chain.

    Parameters
    ----------
    n_qubits : int
        Number of qubits, must be >= 2 (a single qubit has no partner to
        entangle with, so an n=1 "GHZ state" is undefined here).

    Returns
    -------
    list[tuple]
        e.g. ghz_state(3) == [('h', 0), ('cx', 0, 1), ('cx', 1, 2)]

    Examples
    --------
    >>> import dense_evolution as de
    >>> sim = de.DenseSVSimulator(3)
    >>> sim.run_circuit(de.ghz_state(3))
    >>> sim.get_probabilities()[[0, 7]]  # |000> and |111>, each 0.5
    """
    if n_qubits < 2:
        raise ValueError(f"ghz_state needs at least 2 qubits, got {n_qubits}")
    return [('h', 0)] + entangling_layer(n_qubits, pattern='linear', gate='cx')