Source code for toqito.states.ghz

"""GHZ state."""
import numpy as np

from scipy import sparse


[docs] def ghz(dim: int, num_qubits: int, coeff: list[int] = None) -> sparse: r""" Generate a (generalized) GHZ state [GHZ07]_. Returns a :code:`num_qubits`-partite GHZ state acting on :code:`dim` local dimensions, described in [GHZ07]_. For example, :code:`ghz(2, 3)` returns the standard 3-qubit GHZ state on qubits. The output of this function is sparse. For a system of :code:`num_qubits` qubits (i.e., :code:`dim = 2`), the GHZ state can be written as .. math:: |GHZ \rangle = \frac{1}{\sqrt{n}} \left(|0\rangle^{\otimes n} + |1 \rangle^{\otimes n} \right)). Examples ========== When :code:`dim = 2`, and :code:`num_qubits = 3` this produces the standard GHZ state .. math:: \frac{1}{\sqrt{2}} \left( |000 \rangle + |111 \rangle \right). Using :code:`toqito`, we can see that this yields the proper state. >>> from toqito.states import ghz >>> ghz(2, 3).toarray() [[0.70710678], [0. ], [0. ], [0. ], [0. ], [0. ], [0. ], [0.70710678]] As this function covers the generalized GHZ state, we can consider higher dimensions. For instance here is the GHZ state in :math:`\mathbb{C}^{4^{\otimes 7}}` as .. math:: \frac{1}{\sqrt{30}} \left(|0000000 \rangle + 2|1111111 \rangle + 3|2222222 \rangle + 4|3333333\rangle \right). Using :code:`toqito`, we can see this generates the appropriate generalized GHZ state. >>> from toqito.states import ghz >>> ghz(4, 7, np.array([1, 2, 3, 4]) / np.sqrt(30)).toarray() [[0.18257419], [0. ], [0. ], ..., [0. ], [0. ], [0.73029674]]) References ========== .. [GHZ07] Going beyond Bell's theorem. D. Greenberger and M. Horne and A. Zeilinger. E-print: [quant-ph] arXiv:0712.0921. 2007. :raises ValueError: Number of qubits is not a positive integer. :param dim: The local dimension. :param num_qubits: The number of parties (qubits/qudits) :param coeff: (default `[1, 1, ..., 1])/sqrt(dim)`: a 1-by-`dim` vector of coefficients. :returns: Numpy vector array as GHZ state. """ if coeff is None: coeff = np.ones(dim) / np.sqrt(dim) # Error checking: if dim < 1: raise ValueError("InvalidDim: `dim` must be at least 1.") if num_qubits < 1: raise ValueError("InvalidNumQubits: `num_qubits` must be at least 1.") if len(coeff) != dim: raise ValueError( "InvalidCoeff: The variable `coeff` must be a vector of length equal to `dim`." ) # Construct the state (and do it in a way that is less memory-intensive # than naively tensoring things together. dim_sum = 1 for i in range(1, num_qubits): dim_sum += dim**i ret_ghz_state = sparse.lil_matrix((dim**num_qubits, 1)) for i in range(1, dim + 1): ret_ghz_state[(i - 1) * dim_sum] = coeff[i - 1] return ret_ghz_state