quimb ===== .. py:module:: quimb .. autoapi-nested-parse:: Quantum Information for Many-Body calculations. Submodules ---------- .. toctree:: :maxdepth: 1 /autoapi/quimb/_version/index /autoapi/quimb/calc/index /autoapi/quimb/core/index /autoapi/quimb/evo/index /autoapi/quimb/experimental/index /autoapi/quimb/gates/index /autoapi/quimb/gen/index /autoapi/quimb/linalg/index /autoapi/quimb/schematic/index /autoapi/quimb/tensor/index /autoapi/quimb/utils/index Attributes ---------- .. autoapisummary:: quimb.qu quimb.ket quimb.bra quimb.dop quimb.sparse quimb.eye quimb.speye quimb.expec quimb.nmlz quimb.tr quimb.ptr quimb.eig quimb.eigh quimb.eigvals quimb.eigvalsh quimb.eigvecs quimb.eigvecsh quimb.Rx quimb.Ry quimb.Rz quimb.cswap quimb.fredkin quimb.toffoli quimb.zplus quimb.zminus quimb.xplus quimb.xminus quimb.rand_mps quimb.entropy_subsys quimb.mutual_information quimb.tr_sqrt_subsys quimb.logarithmic_negativity quimb.pauli_decomp quimb.bell_decomp quimb.NEUTRAL_STYLE Classes ------- .. autoapisummary:: quimb.qarray quimb.Lazy quimb.Evolution quimb.oset quimb.LRU Functions --------- .. autoapisummary:: quimb.prod quimb.isket quimb.isbra quimb.isop quimb.isvec quimb.issparse quimb.isdense quimb.isreal quimb.isherm quimb.ispos quimb.mul quimb.dag quimb.dot quimb.vdot quimb.rdot quimb.ldmul quimb.rdmul quimb.outer quimb.explt quimb.get_thread_pool quimb.normalize quimb.chop quimb.quimbify quimb.infer_size quimb.trace quimb.identity quimb.dim_map quimb.dim_compress quimb.kron quimb.kronpow quimb.ikron quimb.pkron quimb.permute quimb.itrace quimb.partial_trace quimb.expectation quimb.eigensystem quimb.eigensystem_partial quimb.groundstate quimb.groundenergy quimb.bound_spectrum quimb.eigh_window quimb.eigvalsh_window quimb.eigvecsh_window quimb.svd quimb.svds quimb.norm quimb.expm quimb.sqrtm quimb.expm_multiply quimb.rsvd quimb.estimate_rank quimb.get_mpi_pool quimb.can_use_mpi_pool quimb.spin_operator quimb.pauli quimb.hadamard quimb.phase_gate quimb.S_gate quimb.T_gate quimb.U_gate quimb.rotation quimb.Xsqrt quimb.Ysqrt quimb.Zsqrt quimb.Wsqrt quimb.swap quimb.iswap quimb.fsim quimb.fsimg quimb.ncontrolled_gate quimb.controlled quimb.CNOT quimb.cX quimb.cY quimb.cZ quimb.ccX quimb.ccY quimb.ccZ quimb.controlled_swap quimb.ham_heis quimb.ham_ising quimb.ham_XY quimb.ham_XXZ quimb.ham_j1j2 quimb.ham_mbl quimb.ham_heis_2D quimb.zspin_projector quimb.create quimb.destroy quimb.num quimb.ham_hubbard_hardcore quimb.basis_vec quimb.up quimb.down quimb.plus quimb.minus quimb.yplus quimb.yminus quimb.bloch_state quimb.bell_state quimb.singlet quimb.thermal_state quimb.neel_state quimb.singlet_pairs quimb.werner_state quimb.ghz_state quimb.w_state quimb.levi_civita quimb.perm_state quimb.graph_state_1d quimb.computational_state quimb.randn quimb.rand quimb.rand_matrix quimb.rand_herm quimb.rand_pos quimb.rand_rho quimb.rand_ket quimb.rand_uni quimb.rand_haar_state quimb.gen_rand_haar_states quimb.rand_mix quimb.rand_product_state quimb.rand_matrix_product_state quimb.rand_seperable quimb.rand_iso quimb.rand_mera quimb.seed_rand quimb.set_rand_bitgen quimb.fidelity quimb.purify quimb.entropy quimb.mutinf quimb.mutinf_subsys quimb.schmidt_gap quimb.tr_sqrt quimb.partial_transpose quimb.negativity quimb.logneg quimb.logneg_subsys quimb.concurrence quimb.one_way_classical_information quimb.quantum_discord quimb.trace_distance quimb.cprint quimb.decomp quimb.correlation quimb.pauli_correlations quimb.ent_cross_matrix quimb.qid quimb.is_degenerate quimb.is_eigenvector quimb.page_entropy quimb.heisenberg_energy quimb.dephase quimb.kraus_op quimb.projector quimb.measure quimb.simulate_counts quimb.approx_spectral_function quimb.tr_abs_approx quimb.tr_exp_approx quimb.tr_sqrt_approx quimb.tr_xlogx_approx quimb.entropy_subsys_approx quimb.logneg_subsys_approx quimb.negativity_subsys_approx quimb.xlogx quimb.save_to_disk quimb.load_from_disk quimb.tree_map quimb.tree_apply quimb.tree_flatten quimb.tree_unflatten quimb.format_number_with_error quimb.default_to_neutral_style Package Contents ---------------- .. py:class:: qarray(shape, dtype=float, buffer=None, offset=0, strides=None, order=None) Bases: :py:obj:`numpy.ndarray` Thin subclass of :class:`numpy.ndarray` with some convenient quantum linear algebra related methods and attributes (``.H``, ``&``, etc.), and matrix-like preservation of at least 2-dimensions so as to distiguish kets and bras. .. py:property:: H .. py:method:: toarray() .. py:property:: A .. py:method:: __array__() .. py:method:: __and__(other) .. py:method:: normalize(inplace=True) .. py:method:: nmlz(inplace=True) .. py:method:: chop(inplace=True) .. py:method:: tr() .. py:method:: partial_trace(dims, keep) .. py:method:: ptr(dims, keep) .. py:method:: __array_function__(func, types, args, kwargs) .. py:method:: __str__() .. py:method:: __repr__() .. py:function:: prod(iterable) .. py:function:: isket(qob) Checks if ``qob`` is in ket form -- an array column. .. py:function:: isbra(qob) Checks if ``qob`` is in bra form -- an array row. .. py:function:: isop(qob) Checks if ``qob`` is an operator. .. py:function:: isvec(qob) Checks if ``qob`` is row-vector, column-vector or one-dimensional. .. py:function:: issparse(qob) Checks if ``qob`` is explicitly sparse. .. py:function:: isdense(qob) Checks if ``qob`` is explicitly dense. .. py:function:: isreal(qob, **allclose_opts) Checks if ``qob`` is approximately real. .. py:function:: isherm(qob, **allclose_opts) Checks if ``qob`` is hermitian. :param qob: Matrix to check. :type qob: dense or sparse operator :rtype: bool .. py:function:: ispos(qob, tol=1e-15) Checks if the dense hermitian ``qob`` is approximately positive semi-definite, using the cholesky decomposition. :param qob: Matrix to check. :type qob: dense operator :rtype: bool .. py:function:: mul(x, y) Element-wise multiplication, dispatched to correct dense or sparse function. :param x: First array. :type x: dense or sparse operator :param y: Second array. :type y: dense or sparse operator :returns: Element wise product of ``x`` and ``y``. :rtype: dense or sparse operator .. py:function:: dag(qob) Conjugate transpose. .. py:function:: dot(a, b) Matrix multiplication, dispatched to dense or sparse functions. :param a: First array. :type a: dense or sparse operator :param b: Second array. :type b: dense or sparse operator :returns: Dot product of ``a`` and ``b``. :rtype: dense or sparse operator .. py:function:: vdot(a, b) Accelerated 'Hermitian' inner product of two arrays. In other words, ``b`` here will be conjugated by the function. .. py:function:: rdot(a, b) Real dot product of two dense vectors. Here, ``b`` will *not* be conjugated before the inner product. .. py:function:: ldmul(diag, mat) Accelerated left diagonal multiplication. Equivalent to ``numpy.diag(diag) @ mat``, but faster than numpy. :param diag: Vector representing the diagonal of a matrix. :type diag: vector or 1d-array :param mat: A normal (non-diagonal) matrix. :type mat: dense or sparse matrix :returns: Dot product of the matrix whose diagonal is ``diag`` and ``mat``. :rtype: dense or sparse matrix .. py:function:: rdmul(mat, diag) Accelerated left diagonal multiplication. Equivalent to ``mat @ numpy.diag(diag)``, but faster. :param mat: A normal (non-diagonal) matrix. :type mat: dense or sparse matrix :param diag: Vector representing the diagonal of a matrix. :type diag: vector or 1d-array :returns: Dot product of ``mat`` and the matrix whose diagonal is ``diag``. :rtype: dense or sparse matrix .. py:function:: outer(a, b) Outer product between two vectors (no conjugation). .. py:function:: explt(l, t) Complex exponenital as used in solution to schrodinger equation. .. py:function:: get_thread_pool(num_workers=None) .. py:function:: normalize(qob, inplace=True) Normalize a quantum object. :param qob: Quantum object to normalize. :type qob: dense or sparse vector or operator :param inplace: Whether to act inplace on the given operator. :type inplace: bool, optional :returns: Normalized quantum object. :rtype: dense or sparse vector or operator .. py:function:: chop(qob, tol=1e-15, inplace=True) Set small values of a dense or sparse array to zero. :param qob: Quantum object to chop. :type qob: dense or sparse vector or operator :param tol: Fraction of ``max(abs(qob))`` to chop below. :type tol: float, optional :param inplace: Whether to act on input array or return copy. :type inplace: bool, optional :returns: Chopped quantum object. :rtype: dense or sparse vector or operator .. py:function:: quimbify(data, qtype=None, normalized=False, chopped=False, sparse=None, stype=None, dtype=complex) Converts data to 'quantum' i.e. complex matrices, kets being columns. :param data: Array describing vector or operator. :type data: dense or sparse array_like :param qtype: Quantum object type output type. Note that if an operator is given as ``data`` and ``'ket'`` or ``'bra'`` as ``qtype``, the operator will be unravelled into a column or row vector. :type qtype: {``'ket'``, ``'bra'`` or ``'dop'``}, optional :param sparse: Whether to convert output to sparse a format. :type sparse: bool, optional :param normalized: Whether to normalise the output. :type normalized: bool, optional :param chopped: Whether to trim almost zero entries of the output. :type chopped: bool, optional :param stype: Format of output matrix if sparse, defaults to ``'csr'``. :type stype: {``'csr'``, ``'csc'``, ``'bsr'``, ``'coo'``}, optional :rtype: dense or sparse vector or operator .. rubric:: Notes 1. Will unravel an array if ``'ket'`` or ``'bra'`` given. 2. Will conjugate if ``'bra'`` given. 3. Will leave operators as is if ``'dop'`` given, but construct one if vector given with the assumption that it was a ket. .. rubric:: Examples Create a ket (column vector): >>> qu([1, 2j, 3]) qarray([[1.+0.j], [0.+2.j], [3.+0.j]]) Create a single precision bra (row vector): >>> qu([1, 2j, 3], qtype='bra', dtype='complex64') qarray([[1.-0.j, 0.-2.j, 3.-0.j]], dtype=complex64) Create a density operator from a vector: >>> qu([1, 2j, 3], qtype='dop') qarray([[1.+0.j, 0.-2.j, 3.+0.j], [0.+2.j, 4.+0.j, 0.+6.j], [3.+0.j, 0.-6.j, 9.+0.j]]) Create a sparse density operator: >>> qu([1, 0, 0], sparse=True, qtype='dop') <3x3 sparse matrix of type '' with 1 stored elements in Compressed Sparse Row format> .. py:data:: qu Alias of :func:`quimbify`. .. py:data:: ket Convert an object into a ket. .. py:data:: bra Convert an object into a bra. .. py:data:: dop Convert an object into a density operator. .. py:data:: sparse Convert an object into sparse form. .. py:function:: infer_size(p, base=2) Infer the size, i.e. number of 'sites' in a state. :param p: An array representing a state with a shape attribute. :type p: vector or operator :param base: Size of the individual states that ``p`` is composed of, e.g. this defauts 2 for qubits. :type base: int, optional :returns: Number of composite systems. :rtype: int .. rubric:: Examples >>> infer_size(singlet() & singlet()) 4 >>> infersize(rand_rho(5**3), base=5) 3 .. py:function:: trace(mat) Trace of a dense or sparse operator. :param mat: Operator, dense or sparse. :type mat: operator :returns: **x** -- Trace of ``mat`` :rtype: float .. py:function:: identity(d, sparse=False, stype='csr', dtype=complex) Return identity of size d in complex format, optionally sparse. :param d: Dimension of identity. :type d: int :param sparse: Whether to output in sparse form. :type sparse: bool, optional :param stype: If sparse, what format to use. :type stype: str, optional :returns: **id** -- Identity operator. :rtype: qarray or sparse matrix .. py:data:: eye Alias for :func:`identity`. .. py:data:: speye Sparse identity. .. py:function:: dim_map(dims, coos, cyclic=False, trim=False) Flatten 2d+ dimensions and coordinates. Maps multi-dimensional coordinates and indices to flat arrays in a regular way. Wraps or deletes coordinates beyond the system size depending on parameters ``cyclic`` and ``trim``. :param dims: Multi-dim array of systems' internal dimensions. :type dims: nested tuple of int :param coos: Array of coordinate tuples to convert :type coos: list of tuples of int :param cyclic: Whether to automatically wrap coordinates beyond system size or delete them. :type cyclic: bool, optional :param trim: If True, any coordinates beyond dimensions will be deleted, overidden by cyclic. :type trim: bool, optional :returns: * **flat_dims** (*tuple*) -- Flattened version of ``dims``. * **inds** (*tuple*) -- Indices corresponding to the original coordinates. .. rubric:: Examples >>> dims = [[2, 3], [4, 5]] >>> coords = [(0, 0), (1, 1)] >>> flat_dims, inds = dim_map(dims, coords) >>> flat_dims (2, 3, 4, 5) >>> inds (0, 3) >>> dim_map(dims, [(2, 0), (-1, 1)], cyclic=True) ((2, 3, 4, 5), (0, 3)) .. py:function:: dim_compress(dims, inds) Compress neighbouring subsytem dimensions. Take some dimensions and target indices and compress both, i.e. merge adjacent dimensions that are both either in ``dims`` or not. For example, if tensoring an operator onto a single site, with many sites the identity, treat these as single large identities. :param dims: List of system's dimensions - 1d or flattened (e.g. with ``dim_map``). :type dims: tuple of int :param inds: List of target indices, i.e. dimensions not to merge. :type inds: tuple of int :returns: * **dims** (*tuple of int*) -- New compressed dimensions. * **inds** (*tuple of int*) -- New indexes corresponding to the compressed dimensions. These are guaranteed to now be alternating i.e. either (0, 2, ...) or (1, 3, ...). .. rubric:: Examples >>> dims = [2] * 10 >>> inds = [3, 4] >>> compressed_dims, compressed_inds = dim_compress(dims, inds) >>> compressed_dims (8, 4, 32) >>> compressed_inds (1,) .. py:function:: kron(*ops, stype=None, coo_build=False, parallel=False, ownership=None) Tensor (kronecker) product of variable number of arguments. :param ops: Objects to be tensored together. :type ops: sequence of vectors or matrices :param stype: Desired output format if resultant object is sparse. Should be one of {``'csr'``, ``'bsr'``, ``'coo'``, ``'csc'``}. If ``None``, infer from input matrices. :type stype: str, optional :param coo_build: Whether to force sparse construction to use the ``'coo'`` format (only for sparse matrices in the first place.). :type coo_build: bool, optional :param parallel: Perform a parallel reduce on the operators, can be quicker. :type parallel: bool, optional :param ownership: If given, only construct the rows in ``range(*ownership)``. Such that the final operator is actually ``X[slice(*ownership), :]``. Useful for constructing operators in parallel, e.g. for MPI. :type ownership: (int, int), optional :returns: **X** -- Tensor product of ``ops``. :rtype: dense or sparse vector or operator .. rubric:: Notes 1. The product is performed as ``(a & (b & (c & ...)))`` .. rubric:: Examples Simple example: >>> a = np.array([[1, 2], [3, 4]]) >>> b = np.array([[1., 1.1], [1.11, 1.111]]) >>> kron(a, b) qarray([[1. , 1.1 , 2. , 2.2 ], [1.11 , 1.111, 2.22 , 2.222], [3. , 3.3 , 4. , 4.4 ], [3.33 , 3.333, 4.44 , 4.444]]) Partial construction of rows: >>> ops = [rand_matrix(2, sparse=True) for _ in range(10)] >>> kron(*ops, ownership=(256, 512)) <256x1024 sparse matrix of type '' with 13122 stored elements in Compressed Sparse Row format> .. py:function:: kronpow(a, p, **kron_opts) Returns `a` tensored with itself `p` times Equivalent to ``reduce(lambda x, y: x & y, [a] * p)``. :param a: Object to tensor power. :type a: dense or sparse vector or operator :param p: Tensor power. :type p: int :param kron_opts: Supplied to :func:`~quimb.kron`. :rtype: dense or sparse vector or operator .. py:function:: ikron(ops, dims, inds, sparse=None, stype=None, coo_build=False, parallel=False, ownership=None) Tensor an operator into a larger space by padding with identities. Automatically placing a large operator over several dimensions is allowed and a list of operators can be given which are then placed cyclically. :param op: Operator(s) to place into the tensor space. If more than one, these are cyclically placed at each of the ``dims`` specified by ``inds``. :type op: operator or sequence of operators :param dims: The subsystem dimensions. If treated as an array, should have the same number of dimensions as the system. :type dims: sequence of int or nested sequences of int :param inds: Indices, or coordinates, of the dimensions to place operator(s) on. Each dimension specified can be smaller than the size of ``op`` (as long as it factorizes it). :type inds: tuple of int, or sequence of tuple of int :param sparse: Whether to construct the new operator in sparse form. :type sparse: bool, optional :param stype: If sparse, which format to use for the output. :type stype: str, optional :param coo_build: Whether to build the intermediary matrices using the ``'coo'`` format - can be faster to build sparse in this way, then convert to chosen format, including dense. :type coo_build: bool, optional :param parallel: Whether to build the operator in parallel using threads (only good for big (d > 2**16) operators). :type parallel: bool, optional :param ownership: If given, only construct the rows in ``range(*ownership)``. Such that the final operator is actually ``X[slice(*ownership), :]``. Useful for constructing operators in parallel, e.g. for MPI. :type ownership: (int, int), optional :returns: Operator such that ops act on ``dims[inds]``. :rtype: qarray or sparse matrix .. seealso:: :obj:`kron`, :obj:`pkron` .. rubric:: Examples Place an operator between two identities: >>> IZI = ikron(pauli('z'), [2, 2, 2], 1) >>> np.allclose(IZI, eye(2) & pauli('z') & eye(2)) True Overlay a large operator on several sites: >>> rho_ab = rand_rho(4) >>> rho_abc = ikron(rho_ab, [5, 2, 2, 7], [1, 2]) # overlay both 2s >>> rho_abc.shape (140, 140) Place an operator at specified sites, regardless of size: >>> A = rand_herm(5) >>> ikron(A, [2, -1, 2, -1, 2, -1], [1, 3, 5]).shape (1000, 1000) Create a two site interaction (note the coefficient `jx` we only need to multiply into a single input operator): >>> Sx = spin_operator('X') >>> jx = 0.123 >>> jSxSx = ikron([jx * Sx, Sx], [2, 2, 2, 2], [0, 3]) >>> np.allclose(jSxSx, jx * (Sx & eye(2) & eye(2) & Sx)) True .. py:function:: pkron(op, dims, inds, **ikron_opts) Advanced, padded tensor product. Construct an operator such that ``op`` acts on ``dims[inds]``, and allow it to be arbitrarily split and reversed etc., in other words, permute and then tensor it into a larger space. :param ops: Operator to place into the tensor space. :type ops: matrix-like or tuple of matrix-like :param dims: Dimensions of tensor space. :type dims: tuple of int :param inds: Indices of the dimensions to place operators on. If multiple operators are specified, ``inds[1]`` corresponds to ``ops[1]`` and so on. :type inds: tuple of int :param sparse: Whether to construct the new operator in sparse form. :type sparse: bool, optional :param stype: If sparse, which format to use for the output. :type stype: str, optional :param coo_build: Whether to build the intermediary matrices using the ``'coo'`` format - can be faster to build sparse in this way, then convert to chosen format, including dense. :type coo_build: bool, optional :returns: Operator such that ops act on ``dims[inds]``. :rtype: operator .. seealso:: :obj:`ikron`, :obj:`permute` .. rubric:: Examples Here we take an operator that acts on spins 0 and 1 with X and Z, and transform it to act on spins 2 and 0 -- i.e. reverse it and sandwich an identity between the two sites it acts on. >>> XZ = pauli('X') & pauli('Z') >>> ZIX = pkron(XZ, dims=[2, 3, 2], inds=[2, 0]) >>> np.allclose(ZIX, pauli('Z') & eye(3) & pauli('X')) True .. py:function:: permute(p, dims, perm) Permute the subsytems of state or opeator. :param p: State or operator to permute. :type p: vector or operator :param dims: Internal dimensions of the system. :type dims: tuple of int :param perm: New order of indexes ``range(len(dims))``. :type perm: tuple of int :returns: **pp** -- Permuted state or operator. :rtype: vector or operator .. seealso:: :obj:`pkron` .. rubric:: Examples >>> IX = speye(2) & pauli('X', sparse=True) >>> XI = permute(IX, dims=[2, 2], perm=[1, 0]) >>> np.allclose(XI.toarray(), pauli('X') & eye(2)) True .. py:function:: itrace(a, axes=(0, 1)) General tensor trace, i.e. multiple contractions, for a dense array. :param a: Tensor to trace. :type a: numpy.ndarray :param axes: - (2,) int: Perform trace on the two indices listed. - (2,) array of int: Trace out first sequence of indices with second sequence indices. :type axes: (2,) int or (2,) array of int :returns: The tensor remaining after tracing out the specified axes. :rtype: numpy.ndarray .. seealso:: :obj:`trace`, :obj:`partial_trace` .. rubric:: Examples Trace out a single pair of dimensions: >>> a = randn(2, 3, 4, 2, 3, 4) >>> itrace(a, axes=(0, 3)).shape (3, 4, 3, 4) Trace out multiple dimensions: >>> itrace(a, axes=([1, 2], [4, 5])).shape (2, 2) .. py:function:: partial_trace(p, dims, keep) Partial trace of a dense or sparse state. :param p: State to perform partial trace on - can be sparse. :type p: ket or density operator :param dims: The subsystem dimensions. If treated as an array, should have the same number of dimensions as the system. :type dims: sequence of int or nested sequences of int :param keep: Index or indices of subsytem(s) to keep. If a sequence of integer tuples, each should be a coordinate such that the length matches the number of dimensions of the system. :type keep: int, sequence of int or sequence of tuple[int] :returns: **rho** -- Density operator of subsytem dimensions ``dims[keep]``. :rtype: qarray .. seealso:: :obj:`itrace` .. rubric:: Examples Trace out single subsystem of a ket: >>> psi = bell_state('psi-') >>> ptr(psi, [2, 2], keep=0) # expect identity qarray([[ 0.5+0.j, 0.0+0.j], [ 0.0+0.j, 0.5+0.j]]) Trace out multiple subsystems of a density operator: >>> rho_abc = rand_rho(3 * 4 * 5) >>> rho_ab = partial_trace(rho_abc, [3, 4, 5], keep=[0, 1]) >>> rho_ab.shape (12, 12) Trace out qutrits from a 2D system: >>> psi_abcd = rand_ket(3 ** 4) >>> dims = [[3, 3], ... [3, 3]] >>> keep = [(0, 0), (1, 1)] >>> rho_ac = partial_trace(psi_abcd, dims, keep) >>> rho_ac.shape (9, 9) .. py:function:: expectation(a, b) 'Expectation' between a vector/operator and another vector/operator. The 'operator' inner product between ``a`` and ``b``, but also for vectors. This means that for consistency: - for two vectors it will be the absolute expec squared ``||``, *not* ````. - for a vector and an operator its will be ```` - for two operators it will be the Hilbert-schmidt inner product ``tr(A @ B)`` In this way ``expectation(a, b) == expectation(dop(a), b) == expectation(dop(a), dop(b))``. :param a: First state or operator - assumed to be ket if vector. :type a: vector or operator :param b: Second state or operator - assumed to be ket if vector. :type b: vector or operator :returns: **x** -- 'Expectation' of ``a`` with ``b``. :rtype: float .. py:data:: expec Alias for :func:`expectation`. .. py:data:: nmlz Alias for :func:`normalize`. .. py:data:: tr Alias for :func:`trace`. .. py:data:: ptr Alias for :func:`partial_trace`. .. py:function:: eigensystem(A, isherm, *, k=-1, sort=True, return_vecs=True, **kwargs) Find all or some eigenpairs of an operator. :param A: The operator to decompose. :type A: operator :param isherm: Whether the operator is assumed to be hermitian or not. :type isherm: bool :param k: If negative, find all eigenpairs, else perform partial eigendecomposition and find ``k`` pairs. See :func:`~quimb.linalg.base_linalg.eigensystem_partial`. :type k: int, optional :param sort: Whether to sort the eigenpairs in ascending eigenvalue order. :type sort: bool, optional :param kwargs: Supplied to the backend function. :returns: * **el** (*(k,) array*) -- Eigenvalues. * **ev** (*(d, k) array*) -- Corresponding eigenvectors as columns of array, such that ``ev @ diag(el) @ ev.H == A``. .. py:data:: eig .. py:data:: eigh .. py:data:: eigvals .. py:data:: eigvalsh .. py:data:: eigvecs .. py:data:: eigvecsh .. py:function:: eigensystem_partial(A, k, isherm, *, B=None, which=None, return_vecs=True, sigma=None, ncv=None, tol=None, v0=None, sort=True, backend=None, fallback_to_scipy=False, **backend_opts) Return a few eigenpairs from an operator. :param A: The operator to solve for. :type A: sparse, dense or linear operator :param k: Number of eigenpairs to return. :type k: int :param isherm: Whether to use hermitian solve or not. :type isherm: bool :param B: If given, the RHS operator defining a generalized eigen problem. :type B: sparse, dense or linear operator, optional :param which: Where in spectrum to take eigenvalues from (see :func:``scipy.sparse.linalg.eigsh``) :type which: {'SA', 'LA', 'LM', 'SM', 'TR'} :param return_vecs: Whether to return the eigenvectors. :type return_vecs: bool, optional :param sigma: Which part of spectrum to target, implies which='TR' if which is None. :type sigma: float, optional :param ncv: number of lanczos vectors, can use to optimise speed :type ncv: int, optional :param tol: Tolerance with which to find eigenvalues. :type tol: None or float :param v0: An initial vector guess to iterate with. :type v0: None or 1D-array like :param sort: Whether to explicitly sort by ascending eigenvalue order. :type sort: bool, optional :param backend: 'LOBPCG', 'SLEPC', 'SLEPC-NOMPI'}, optional Which solver to use. :type backend: {'AUTO', 'NUMPY', 'SCIPY', :param fallback_to_scipy: If an error occurs and scipy is not being used, try using scipy. :type fallback_to_scipy: bool, optional :param backend_opts: Supplied to the backend solver. :returns: * **elk** (*(k,) array*) -- The ``k`` eigenvalues. * **evk** (*(d, k) array*) -- Array with ``k`` eigenvectors as columns if ``return_vecs``. .. py:function:: groundstate(ham, **kwargs) Alias for finding lowest eigenvector only. .. py:function:: groundenergy(ham, **kwargs) Alias for finding lowest eigenvalue only. .. py:function:: bound_spectrum(A, backend='auto', **kwargs) Return the smallest and largest eigenvalue of hermitian operator ``A``. .. py:function:: eigh_window(A, w_0, k, w_sz=None, backend='AUTO', return_vecs=True, offset_const=1 / 104729, **kwargs) Return mid-spectrum eigenpairs from a hermitian operator. :param A: Operator to retrieve eigenpairs from. :type A: (d, d) operator :param w_0: Relative window centre to retrieve eigenpairs from. :type w_0: float [0.0, 1.0] :param k: Target number of eigenpairs to retrieve. :type k: int :param w_sz: Relative maximum window width within which to keep eigenpairs. :type w_sz: float, optional :param backend: Which :func:`~quimb.eigh` backend to use. :type backend: str, optional :param return_vecs: Whether to return eigenvectors as well. :type return_vecs: bool, optional :param offset_const: Small fudge factor (relative to window range) to avoid 1 / 0 issues. :type offset_const: float, optional :returns: * **el** (*(k,) array*) -- Eigenvalues around w_0. * **ev** (*(d, k) array*) -- The eigenvectors, if ``return_vecs=True``. .. py:function:: eigvalsh_window(*args, **kwargs) Alias for only finding the eigenvalues in a relative window. .. py:function:: eigvecsh_window(*args, **kwargs) Alias for only finding the eigenvectors in a relative window. .. py:function:: svd(A, return_vecs=True) Compute full singular value decomposition of an operator, using numpy. :param A: The operator. :type A: (m, n) array :param return_vecs: Whether to return the singular vectors. :type return_vecs: bool, optional :returns: * **U** (*(m, k) array*) -- Left singular vectors (if ``return_vecs=True``) as columns. * **s** (*(k,) array*) -- Singular values. * **VH** (*(k, n) array*) -- Right singular vectors (if ``return_vecs=True``) as rows. .. py:function:: svds(A, k, ncv=None, return_vecs=True, backend='AUTO', **kwargs) Compute the partial singular value decomposition of an operator. :param A: The operator to decompose. :type A: dense, sparse or linear operator :param k: number of singular value (triplets) to retrieve :type k: int, optional :param ncv: Number of lanczos vectors to use performing decomposition. :type ncv: int, optional :param return_vecs: Whether to return the left and right vectors :type return_vecs: bool, optional :param backend: Which solver to use to perform decomposition. :type backend: {'AUTO', 'SCIPY', 'SLEPC', 'SLEPC-NOMPI', 'NUMPY'}, optional :returns: Singular value(s) (and vectors) such that ``Uk @ np.diag(sk) @ VHk`` approximates ``A``. :rtype: (Uk,) sk (, VHk) .. py:function:: norm(A, ntype=2, **kwargs) Operator norms. :param A: The operator to find norm of. :type A: operator :param ntype: Norm to calculate, if any of: - {2, '2', 'spectral'}: largest singular value - {'f', 'fro'}: frobenius norm - {'t', 'nuc', 'tr', 'trace'}: sum of singular values :type ntype: str :returns: **x** -- The operator norm. :rtype: float .. py:function:: expm(A, herm=False) Matrix exponential, can be accelerated if explicitly hermitian. :param A: Operator to exponentiate. :type A: dense or sparse operator :param herm: If True (not default), and ``A`` is dense, digonalize the matrix in order to perform the exponential. :type herm: bool, optional .. py:function:: sqrtm(A, herm=True) Matrix square root, can be accelerated if explicitly hermitian. :param A: Operator to take square root of. :type A: dense array :param herm: If True (the default), and ``A`` is dense, digonalize the matrix in order to take the square root. :type herm: bool, optional :rtype: array .. py:function:: expm_multiply(mat, vec, backend='AUTO', **kwargs) Compute the action of ``expm(mat)`` on ``vec``. :param mat: Operator with which to act with exponential on ``vec``. :type mat: operator :param vec: Vector to act with exponential of operator on. :type vec: vector-like :param backend: Which backend to use. :type backend: {'AUTO', 'SCIPY', 'SLEPC', 'SLEPC-KRYLOV', 'SLEPC-EXPOKIT'} :param kwargs: Supplied to backend function. :returns: Result of ``expm(mat) @ vec``. :rtype: vector .. py:class:: Lazy(fn, *args, shape=None, factor=None, **kwargs) A simple class representing an unconstructed matrix. This can be passed to, for example, MPI workers, who can then construct the matrix themselves. The main function ``fn`` should ideally take an ``ownership`` keyword to avoid forming every row. This is essentially like using ``functools.partial`` and assigning the ``shape`` attribute. :param fn: A function that constructs an operator. :type fn: callable :param shape: Shape of the constructed operator. :param args: Supplied to ``fn``. :param kwargs: Supplied to ``fn``. :returns: **Lazy** :rtype: callable .. rubric:: Examples Setup the lazy operator: >>> H_lazy = Lazy(ham_heis, n=10, shape=(2**10, 2**10), sparse=True) >>> H_lazy Build a matrix slice (usually done automatically by e.g. ``eigs``): >>> H_lazy(ownership=(256, 512)) <256x1024 sparse matrix of type '' with 1664 stored elements in Compressed Sparse Row format> .. py:attribute:: fn .. py:attribute:: args .. py:attribute:: kwargs .. py:attribute:: shape .. py:attribute:: factor .. py:attribute:: dtype :value: None .. py:method:: __imul__(x) .. py:method:: __mul__(x) .. py:method:: __rmul__(x) .. py:method:: __call__(**kwargs) .. py:method:: __repr__() .. py:function:: rsvd(A, eps_or_k, compute_uv=True, mode='adapt+block', use_qb=20, q=2, p=0, k_max=None, k_start=2, k_incr=1.4, G0=None, AH=None) Fast, randomized, iterative SVD. Adaptive variant of method due originally to Halko. This scales as ``log(k)`` rather than ``k`` so can be more efficient. :param A: The operator to decompose. :type A: operator, shape (m, n) :param eps_or_k: Either the relative precision or the number of singular values to target. If precision, this is relative to the largest singular value. :type eps_or_k: float or int :param compute_uv: Whether to return the left and right singular vectors. :type compute_uv: bool, optional :param mode: How to perform the randomized SVD. If ``eps_or_k`` is an integer then this is implicitly 'block' and ignored. Else: - 'adapt+block', perform an initial low quality pass to estimate the rank of ``A``, then use the subspace and rank from that to perform an accurate fully blocked RSVD. - 'adapt', just perform the adaptive randomized SVD. :type mode: {'adapt+block', 'adapt', 'block'}, optional :param q: The number of power iterations, increase for accuracy at the expense of runtime. :type q: int, optional :param p: Oversampling factor. Perform projections with this many extra columns and then throw then away. :type p: int, optional :param k_max: Maximum adaptive rank. Default: ``min(A.shape)``. :type k_max: int, optional :param k_start: Initial k when increasing rank adaptively. :type k_start: int, optional :param k_incr: Adaptive rank increment factor. Increase the k-step (from k_start) by this factor each time. Set to 1 to use a constant step. :type k_incr: float, optional :param G0: Initial subspace to start iterating on. If not given a random one will be generated. :type G0: array_like, shape (n, k), optional :returns: * *U, array, shape (m, k)* -- Left singular vectors, if ``compute_uv=True``. * *s, array, shape (k,)* -- Singular values. * *V, array, shape (k, n)* -- Right singular vectors, if ``compute_uv=True``. .. py:function:: estimate_rank(A, eps, k_max=None, use_sli=True, k_start=2, k_incr=1.4, q=0, p=0, get_vectors=False, G0=None, AH=None, use_qb=20) Estimate the rank of an linear operator. Uses a low quality random SVD with a resolution of ~ 10. :param A: The operator to find rank of. :type A: linear operator :param eps: Find rank to this relative (compared to largest singular value) precision. :type eps: float :param k_max: The maximum rank to find. :type k_max: int, optional :param use_sli: Whether to use :func:`scipy.linalg.interpolative.estimate_rank` if possible (double precision and no ``k_max`` set). :type use_sli: bool, optional :param k_start: Begin the adaptive SVD with a block of this size. :type k_start: int, optional :param k_incr: Adaptive rank increment factor. Increase the k-step (from k_start) by this factor each time. Set to 1 to use a constant step. :type k_incr: float, optional :param q: Number of power iterations. :type q: int, optional :param get_vectors: Return the right singular vectors found in the pass. :type get_vectors: bool, optional :param G0: :type G0: , optional :returns: * **rank** (*int*) -- The rank. * **VH** (*array*) -- The (adjoint) right singular vectors if ``get_vectors=True``. .. py:function:: get_mpi_pool(num_workers=None, num_threads=1) Get the MPI executor pool, with specified number of processes and threads per process. .. py:function:: can_use_mpi_pool() Function to determine whether we are allowed to call `get_mpi_pool`. .. py:function:: spin_operator(label, S=1 / 2, **kwargs) Generate a general spin-operator. :param label: The type of operator, can be one of six options: - ``{'x', 'X'}``, x-spin operator. - ``{'y', 'Y'}``, y-spin operator. - ``{'z', 'Z'}``, z-spin operator. - ``{'+', 'p'}``, Raising operator. - ``{'-', 'm'}``, Lowering operator. - ``{'i', 'I'}``, identity operator. :type label: str :param S: The spin of particle to act on, default to spin-1/2. :type S: float, optional :param kwargs: Passed to :func:`quimbify`. :returns: **S** -- The spin operator. :rtype: immutable operator .. seealso:: :obj:`pauli` .. rubric:: Examples >>> spin_operator('x') qarray([[0. +0.j, 0.5+0.j], [0.5+0.j, 0. +0.j]]) >>> qu.spin_operator('+', S=1) qarray([[0. +0.j, 1.41421356+0.j, 0. +0.j], [0. +0.j, 0. +0.j, 1.41421356+0.j], [0. +0.j, 0. +0.j, 0. +0.j]]) >>> qu.spin_operator('Y', sparse=True) <2x2 sparse matrix of type '' with 2 stored elements in Compressed Sparse Row format> .. py:function:: pauli(xyz, dim=2, **kwargs) Generates the pauli operators for dimension 2 or 3. :param xyz: Which spatial direction, upper or lower case from ``{'I', 'X', 'Y', 'Z'}``. :type xyz: str :param dim: Dimension of spin operator (e.g. 3 for spin-1), defaults to 2 for spin half. :type dim: int, optional :param kwargs: Passed to ``quimbify``. :returns: **P** -- The pauli operator. :rtype: immutable operator .. seealso:: :obj:`spin_operator` .. py:function:: hadamard(dtype=complex, sparse=False) The Hadamard gate. .. py:function:: phase_gate(phi, dtype=complex, sparse=False) The generalized qubit phase-gate, which adds phase ``phi`` to the ``|1>`` state. .. py:function:: S_gate(dtype=complex, sparse=False) The S-gate (phase gate). .. py:function:: T_gate(dtype=complex, sparse=False) The T-gate (pi/8 gate). .. py:function:: U_gate(theta, phi, lamda, dtype=complex, sparse=False) Arbitrary unitary single qubit gate. .. math:: U_3(\theta, \phi, \lambda) = \begin{bmatrix} \cos(\theta / 2) & - e^{i \lambda} \sin(\theta / 2) \\ e^{i \phi} \sin(\theta / 2) & e^{i(\lambda + \phi)}\cos(\theta / 2) \end{bmatrix} :param theta: Angle between 0 and pi. :type theta: float :param phi: Angle between 0 and 2 pi. :type phi: float :param lamba: Angle between 0 and 2 pi. :type lamba: float :returns: **U** -- The unitary matrix, cached. :rtype: (2, 2) array .. py:function:: rotation(phi, xyz='Z', dtype=complex, sparse=False) The single qubit rotation gate. .. py:data:: Rx .. py:data:: Ry .. py:data:: Rz .. py:function:: Xsqrt(**qu_opts) Rx(pi / 2). .. math:: X^{\frac{1}{2}} = \frac{1}{\sqrt{2}} \begin{bmatrix} 1 & - i \\ - i & 1 \end{bmatrix} .. py:function:: Ysqrt(**qu_opts) Ry(pi / 2). .. math:: Y^{\frac{1}{2}} = \frac{1}{\sqrt{2}} \begin{bmatrix} 1 & - 1 \\ 1 & 1 \end{bmatrix} .. py:function:: Zsqrt(**qu_opts) Rz(pi / 2). .. math:: Z^{\frac{1}{2}} = \frac{1}{\sqrt{2}} \begin{bmatrix} 1 - i & 0 \\ 0 & 1 + i \end{bmatrix} .. py:function:: Wsqrt(**qu_opts) R[X + Y](pi / 2). .. math:: W^{\frac{1}{2}} = \frac{1}{\sqrt{2}} \begin{bmatrix} 1 & -\sqrt{i} \\ \sqrt{-i} & 1 \end{bmatrix} .. py:function:: swap(dim=2, dtype=complex, **kwargs) The SWAP operator acting on subsystems of dimension `dim`. .. py:function:: iswap(dtype=complex, **kwargs) .. py:function:: fsim(theta, phi, dtype=complex, **kwargs) The 'fermionic simulation' gate: .. math:: \mathrm{fsim}(\theta, \phi) = \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & \cos(\theta) & -i sin(\theta) & 0\\ 0 & -i sin(\theta) & \cos(\theta) & 0\\ 0 & 0 & 0 & \exp(-i \phi) \end{bmatrix} Note that ``theta`` and ``phi`` should be specified in radians and the sign convention with this gate varies. Here for example, ``fsim(- pi / 2, 0) == iswap()``. .. py:function:: fsimg(theta, zeta, chi, gamma, phi, dtype=complex, **kwargs) The 'fermionic simulation' gate, with: * :math:`\theta` is the iSWAP angle * :math:`\phi` is the controlled-phase angle * :math:`\zeta, \chi, \gamma` are single-qubit phase angles. .. math:: \mathrm{fsimg}(\theta, \zeta, \chi, \gamma, \phi) = \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & \exp(-i(\gamma +\zeta )) \cos(\theta) & -i \exp(-i(\gamma - \chi )) sin(\theta) & 0\\ 0 & -i \exp(-i(\gamma + \chi )) sin(\theta) & \exp(-i(\gamma - \zeta )) \cos(\theta) & 0\\ 0 & 0 & 0 & \exp(-i (\phi +2 \gamma)) \end{bmatrix} See Equation 18 of https://arxiv.org/abs/2010.07965. Note that ``theta``, ``phi``, ``zeta``, ``chi``, ``gamma`` should be specified in radians and the sign convention with this gate varies. Here for example, ``fsimg(- pi / 2, 0, 0, 0,0) == iswap()``. .. py:function:: ncontrolled_gate(ncontrol, gate, dtype=complex, sparse=False) Build an n-qubit controlled gate. The control qubits are the first ``ncontrol`` qubits. :param ncontrol: The number of control qubits. :type ncontrol: int :param gate: The gate to apply to the controlled qubit(s). :type gate: array_like :param dtype: The data type of the returned matrix. :type dtype: str :param sparse: Whether to return a sparse matrix. :type sparse: bool :returns: **C** -- The n-qubit controlled gate. :rtype: qarray .. py:function:: controlled(s, dtype=complex, sparse=False) Construct a controlled pauli gate for two qubits. :param s: Which pauli to use, including 'not' aliased to 'x'. :type s: str :param sparse: Whether to construct a sparse operator. :type sparse: bool, optional :returns: **C** -- The controlled two-qubit gate operator. :rtype: qarray .. py:function:: CNOT(dtype=complex, sparse=False) The controlled-not gate. .. py:function:: cX(dtype=complex, sparse=False) The controlled-X gate. .. py:function:: cY(dtype=complex, sparse=False) The controlled-Y gate. .. py:function:: cZ(dtype=complex, sparse=False) The controlled-Z gate. .. py:function:: ccX(dtype=complex, sparse=False) The double controlled X gate, or Toffoli gate. .. py:function:: ccY(dtype=complex, sparse=False) The double controlled Y gate. .. py:function:: ccZ(dtype=complex, sparse=False) The double controlled Z gate. .. py:function:: controlled_swap(dtype=complex, sparse=False) The controlled swap or Fredkin gate. The control qubit is the first qubit, if in state |1> a swap is performed on the last two qubits. .. py:data:: cswap .. py:data:: fredkin .. py:data:: toffoli .. py:function:: ham_heis(n, j=1.0, b=0.0, cyclic=False, parallel=False, nthreads=None, ownership=None) Constructs the nearest neighbour 1d heisenberg spin-1/2 hamiltonian. :param n: Number of spins. :type n: int :param j: Coupling constant(s), with convention that positive = antiferromagnetic. Can supply scalar for isotropic coupling or vector ``(jx, jy, jz)``. :type j: float or tuple(float, float, float), optional :param b: Magnetic field, defaults to z-direction only if tuple not given. :type b: float or tuple(float, float, float), optional :param cyclic: Whether to couple the first and last spins. :type cyclic: bool, optional :param sparse: Whether to return the hamiltonian in sparse form. :type sparse: bool, optional :param stype: What format of sparse operator to return if ``sparse``. :type stype: str, optional :param parallel: Whether to build the operator in parallel. By default will do this for n > 16. :type parallel: bool, optional :param nthreads: How mny threads to use in parallel to build the operator. :type nthreads: int optional :param ownership: If given, which range of rows to generate. :type ownership: (int, int), optional :param kwargs: Supplied to :func:`~quimb.core.quimbify`. :returns: **H** -- The Hamiltonian. :rtype: immutable operator .. py:function:: ham_ising(n, jz=1.0, bx=1.0, **ham_opts) Generate the quantum transverse field ising model hamiltonian. This is a simple alias for :func:`~quimb.gen.operators.ham_heis` with Z-interactions and an X-field. .. py:function:: ham_XY(n, jxy, bz, **ham_opts) Generate the quantum transverse field XY model hamiltonian. This is a simple alias for :func:`~quimb.gen.operators.ham_heis` with X- and Y-interactions and a Z-field. .. py:function:: ham_XXZ(n, delta, jxy=1.0, **ham_opts) Generate the XXZ-model hamiltonian. This is a simple alias for :func:`~quimb.gen.operators.ham_heis` with matched X- and Y-interactions and ``delta`` Z coupling. .. py:function:: ham_j1j2(n, j1=1.0, j2=0.5, bz=0.0, cyclic=False, ownership=None) Generate the j1-j2 hamiltonian, i.e. next nearest neighbour interactions. :param n: Number of spins. :type n: int :param j1: Nearest neighbour coupling strength. :type j1: float, optional :param j2: Next nearest neighbour coupling strength. :type j2: float, optional :param bz: B-field strength in z-direction. :type bz: float, optional :param cyclic: Cyclic boundary conditions. :type cyclic: bool, optional :param sparse: Return hamiltonian as sparse-csr operator. :type sparse: bool, optional :param ownership: If given, which range of rows to generate. :type ownership: (int, int), optional :param kwargs: Supplied to :func:`~quimb.core.quimbify`. :returns: **H** -- The Hamiltonian. :rtype: immutable operator .. py:function:: ham_mbl(n, dh, j=1.0, bz=0.0, cyclic=False, seed=None, dh_dist='s', dh_dim=1, beta=None, ownership=None) Constructs a heisenberg hamiltonian with isotropic coupling and random fields acting on each spin - the many-body localized (MBL) spin hamiltonian. :param n: Number of spins. :type n: int :param dh: Strength of random fields (stdev of gaussian distribution), can be scalar (isotropic noise) or 3-vector for (x, y, z) directions. :type dh: float or (float, float, float) :param j: Coupling strength, can be scalar (isotropic) or 3-vector. :type j: float or (float, float, float), optional :param bz: Global magnetic field (in z-direction). :type bz: float, optional :param cyclic: Whether to use periodic boundary conditions. :type cyclic: bool, optional :param seed: Number to seed random number generator with. :type seed: int, optional :param dh_dist: Type of random distribution for the noise: - "s": square, with bounds ``(-dh, dh)`` - "g": gaussian, with standard deviation ``dh`` - "qp": quasi periodic, with amplitude ``dh`` and 'wavenumber' ``beta`` so that the field at site ``i`` is ``dh * cos(2 * pi * beta * i + delta)`` with ``delta`` a random offset between ``(0, 2 * pi)``, possibly seeded by ``seed``. :type dh_dist: {'g', 's', 'qr'}, optional :param dh_dim: The number of dimensions the noise acts in, or string specifier like ``'yz'``. :type dh_dim: {1, 2, 3} or str, optional :param beta: The wave number if ``dh_dist='qr'``, defaults to the golden ratio``(5**0.5 - 1) / 2``. :type beta: float, optional :param sparse: Whether to construct the hamiltonian in sparse form. :type sparse: bool, optional :param stype: The sparse format. :type stype: {'csr', 'csc', 'coo'}, optional :param ownership: If given, which range of rows to generate. :type ownership: (int, int), optional :param kwargs: Supplied to :func:`~quimb.core.quimbify`. :returns: **H** -- The MBL hamiltonian for spin-1/2. :rtype: operator .. seealso:: :obj:`MPO_ham_mbl` .. py:function:: ham_heis_2D(n, m, j=1.0, bz=0.0, cyclic=False, parallel=False, ownership=None) Construct the 2D spin-1/2 heisenberg model hamiltonian: .. math:: \hat{H} = \sum_{} J_X S^X_i S^X_j + J_Y S^Y_i S^Y_j + J_Z S^Z_i S^Z_j where the sum runs over pairs :math:`` on a 2D square lattice. :param n: The number of rows. :type n: int :param m: The number of columns. :type m: int :param j: The coupling strength(s). Isotropic if scalar else if vector ``(Jx, Jy, Jz) = j``. :type j: float or (float, float, float), optional :param bz: The z direction magnetic field. :type bz: float, optional :param cyclic: Whether to use periodic boundary conditions. :type cyclic: bool, optional :param sparse: Whether to construct the hamiltonian in sparse form. :type sparse: bool, optional :param stype: The sparse format. :type stype: {'csr', 'csc', 'coo'}, optional :param parallel: Construct the hamiltonian in parallel. Faster but might use more memory. :type parallel: bool, optional :param ownership: If given, which range of rows to generate. :type ownership: (int, int), optional :param kwargs: Supplied to :func:`~quimb.core.quimbify`. :returns: **H** -- The hamiltonian. :rtype: operator .. py:function:: zspin_projector(n, sz=0, stype='csr', dtype=float) Construct the projector onto spin-z subpspaces. :param n: Total size of spin system. :type n: int :param sz: Spin-z value(s) subspace(s) to find projector for. :type sz: float or sequence of floats :param stype: Sparse format of the output operator. :type stype: str :param dtype: The data type of the operator to generate. :type dtype: {float, complex}, optional :returns: **prj** -- The (non-square) projector onto the specified subspace(s). The subspace size ``D`` is given by ``n choose (n / 2 + s)`` for each ``s`` specified in ``sz``. :rtype: immutable sparse operator, shape (2**n, D) .. rubric:: Examples >>> zspin_projector(n=2, sz=0).toarray() array([[0., 0.], [1., 0.], [0., 1.], [0., 0.]] Project a 9-spin Heisenberg-Hamiltonian into its spin-1/2 subspace: >>> H = ham_heis(9, sparse=True) >>> H.shape (512, 512) >>> P = zspin_projector(n=9, sz=1 / 2) >>> H0 = P.T @ H @ P >>> H0.shape (126, 126) .. py:function:: create(n=2, **qu_opts) The creation operator acting on an n-level system. .. py:function:: destroy(n=2, **qu_opts) The annihilation operator acting on an n-level system. .. py:function:: num(n, **qu_opts) The number operator acting on an n-level system. .. py:function:: ham_hubbard_hardcore(n, t=0.5, V=1.0, mu=1.0, cyclic=False, parallel=False, ownership=None) Generate the spinless fermion hopping hamiltonian. :param n: The number of sites. :type n: int :param t: The hopping energy. :type t: float, optional :param V: The interaction energy. :type V: float, optional :param mu: The chemical potential - defaults to half-filling. :type mu: float, optional :param cyclic: Whether to use periodic boundary conditions. :type cyclic: bool, optional :param parallel: Construct the hamiltonian in parallel. Faster but might use more memory. :type parallel: bool, optional :param ownership: If given, which range of rows to generate. :type ownership: (int, int), optional :param kwargs: Supplied to :func:`~quimb.core.quimbify`. :returns: **H** -- The hamiltonian. :rtype: operator .. py:function:: basis_vec(i, dim, ownership=None, **kwargs) Constructs a unit vector ket: .. math:: |i\rangle = \begin{pmatrix} 0 \\ \vdots \\ 1 \\ \vdots \\ 0 \end{pmatrix} :param i: Which index should the single non-zero, unit entry. :type i: int :param dim: Total size of hilbert space. :type dim: int :param sparse: Return vector as sparse matrix. :type sparse: bool, optional :param kwargs: Supplied to ``qu``. :returns: The basis vector. :rtype: vector .. py:function:: up(**kwargs) Returns up-state, aka. ``|0>``, +Z eigenstate: .. math:: |0\rangle = \begin{pmatrix} 1 \\ 0 \end{pmatrix} .. py:data:: zplus .. py:function:: down(**kwargs) Returns down-state, aka. ``|1>``, -Z eigenstate: .. math:: |1\rangle = \begin{pmatrix} 0 \\ 1 \end{pmatrix} .. py:data:: zminus .. py:function:: plus(**kwargs) Returns plus-state, aka. ``|+>``, +X eigenstate: .. math:: |+\rangle = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 \\ 1 \end{pmatrix} .. py:data:: xplus .. py:function:: minus(**kwargs) Returns minus-state, aka. ``|->``, -X eigenstate: .. math:: |-\rangle = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 \\ -1 \end{pmatrix} .. py:data:: xminus .. py:function:: yplus(**kwargs) Returns yplus-state, aka. ``|y+>``, +Y eigenstate: .. math:: |y+\rangle = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 \\ i \end{pmatrix} .. py:function:: yminus(**kwargs) Returns yplus-state, aka. ``|y->``, -Y eigenstate: .. math:: |y-\rangle = \frac{1}{\sqrt{2}} \begin{pmatrix} 1 \\ -i \end{pmatrix} .. py:function:: bloch_state(ax, ay, az, purified=False, **kwargs) Construct qubit density operator from bloch vector: .. math:: \rho = \frac{1}{2} \left( I + a_x X + a_y Y + a_z Z \right) :param ax: X component of bloch vector. :type ax: float :param ay: Y component of bloch vector. :type ay: float :param az: Z component of bloch vector. :type az: float :param purified: Whether to map vector to surface of bloch sphere. :returns: Density operator of qubit 'pointing' in (ax, ay, az) direction. :rtype: Matrix .. py:function:: bell_state(s, **kwargs) One of the four bell-states. If n = 2**-0.5, they are: 0. ``'psi-'`` : ``n * ( |01> - |10> )`` 1. ``'psi+'`` : ``n * ( |01> + |10> )`` 2. ``'phi-'`` : ``n * ( |00> - |11> )`` 3. ``'phi+'`` : ``n * ( |00> + |11> )`` They can be enumerated in this order. :param s: String of number of state corresponding to above. :type s: str or int :param kwargs: Supplied to ``qu`` called on state. :returns: **p** -- The bell-state ``s``. :rtype: immutable vector .. py:function:: singlet(**kwargs) Alias for the 'psi-' bell-state. .. py:function:: thermal_state(ham, beta, precomp_func=False) Generate a thermal state of a Hamiltonian. :param ham: Hamiltonian, either full or tuple of (evals, evecs). :type ham: operator or (1d-array, 2d-array) :param beta: Inverse temperature of state. :type beta: float :param precomp_func: If True, return a function that takes ``beta`` only and is closed over the solved hamiltonian. :type precomp_func: bool, optional :returns: Density operator of thermal state, or function to generate such given a temperature. :rtype: operator or callable .. py:function:: neel_state(n, down_first=False, **kwargs) Construct Neel state for n spins, i.e. alternating up/down. :param n: Number of spins. :type n: int :param down_first: Whether to start with '1' or '0' first. :type down_first: bool, optional :param kwargs: Supplied to ``qu`` called on state. .. seealso:: :obj:`computational_state`, :obj:`MPS_neel_state` .. py:function:: singlet_pairs(n, **kwargs) Construct fully dimerised spin chain. I.e. ``bell_state('psi-') & bell_state('psi-') & ...`` :param n: Number of spins. :type n: int :param kwargs: Supplied to ``qu`` called on state. :rtype: vector .. py:function:: werner_state(p, **kwargs) Construct Werner State, i.e. fractional mix of identity with singlet. :param p: Singlet Fraction. :type p: float :param kwargs: Supplied to :func:`~quimb.qu` called on state. :rtype: qarray .. py:function:: ghz_state(n, **kwargs) Construct GHZ state of `n` spins, i.e. equal superposition of all up and down. :param n: Number of spins. :type n: int :param kwargs: Supplied to ``qu`` called on state. :rtype: vector .. py:function:: w_state(n, **kwargs) Construct W-state: equal superposition of all single spin up states. :param n: Number of spins. :type n: int :param kwargs: Supplied to ``qu`` called on state. :rtype: vector .. py:function:: levi_civita(perm) Compute the generalised levi-civita coefficient for a permutation. :param perm: The permutation, a re-arrangement of ``range(n)``. :type perm: sequence of int :returns: Either -1, 0 or 1. :rtype: int .. py:function:: perm_state(ps) Construct the anti-symmetric state which is the +- sum of all tensored permutations of states ``ps``. :param ps: The states to combine. :type ps: sequence of states :returns: The permutation state, dimension same as ``kron(*ps)``. :rtype: vector or operator .. rubric:: Examples A singlet is the ``perm_state`` of up and down. >>> states = [up(), down()] >>> pstate = perm_state(states) >>> expec(pstate, singlet()) 1.0 .. py:function:: graph_state_1d(n, cyclic=False, sparse=False) Graph State on a line. :param n: The number of spins. :type n: int :param cyclic: Whether to use cyclic boundary conditions for the graph. :type cyclic: bool, optional :param sparse: Whether to return a sparse state. :type sparse: bool, optional :returns: The 1d-graph state. :rtype: vector .. py:function:: computational_state(binary, **kwargs) Generate the qubit computational state with ``binary``. :param binary: The binary of the computation state. :type binary: sequence of 0s and 1s .. rubric:: Examples >>> computational_state('101'): qarray([[0.+0.j], [0.+0.j], [0.+0.j], [0.+0.j], [0.+0.j], [1.+0.j], [0.+0.j], [0.+0.j]]) >>> qu.computational_state([0, 1], qtype='dop') qarray([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]]) .. seealso:: :obj:`MPS_computational_state`, :obj:`basic_vec` .. py:function:: randn(shape=(), dtype=float, scale=1.0, loc=0.0, num_threads=None, seed=None, dist='normal') Fast multithreaded generation of random normally distributed data. :param shape: The shape of the output random array. :type shape: tuple[int] :param dtype: The data-type of the output array. :type dtype: {'complex128', 'float64', 'complex64' 'float32'}, optional :param scale: A multiplicative scale for the random numbers. :type scale: float, optional :param loc: An additive location for the random numbers. :type loc: float, optional :param num_threads: How many threads to use. If ``None``, decide automatically. :type num_threads: int, optional :param dist: Type of random number to generate. :type dist: {'normal', 'uniform', 'rademacher', 'exp'}, optional .. py:function:: rand(*args, **kwargs) .. py:function:: rand_matrix(d, scaled=True, sparse=False, stype='csr', density=None, dtype=complex, seed=None) Generate a random matrix of order `d` with normally distributed entries. If `scaled` is `True`, then in the limit of large `d` the eigenvalues will be distributed on the unit complex disk. :param d: Matrix dimension. :type d: int :param scaled: Whether to scale the matrices values such that its spectrum approximately lies on the unit disk (for dense matrices). :type scaled: bool, optional :param sparse: Whether to produce a sparse matrix. :type sparse: bool, optional :param stype: The type of sparse matrix if ``sparse=True``. :type stype: {'csr', 'csc', 'coo', ...}, optional :param density: Target density of non-zero elements for the sparse matrix. By default aims for about 10 entries per row. :type density: float, optional :param dtype: The data type of the matrix elements. :type dtype: {complex, float}, optional :returns: **mat** -- Random matrix. :rtype: qarray or sparse matrix .. py:function:: rand_herm(d, sparse=False, density=None, dtype=complex) Generate a random hermitian operator of order `d` with normally distributed entries. In the limit of large `d` the spectrum will be a semi-circular distribution between [-1, 1]. .. seealso:: :obj:`rand_matrix`, :obj:`rand_pos`, :obj:`rand_rho`, :obj:`rand_uni` .. py:function:: rand_pos(d, sparse=False, density=None, dtype=complex) Generate a random positive operator of size `d`, with normally distributed entries. In the limit of large `d` the spectrum will lie between [0, 1]. .. seealso:: :obj:`rand_matrix`, :obj:`rand_herm`, :obj:`rand_rho`, :obj:`rand_uni` .. py:function:: rand_rho(d, sparse=False, density=None, dtype=complex) Generate a random positive operator of size `d` with normally distributed entries and unit trace. .. seealso:: :obj:`rand_matrix`, :obj:`rand_herm`, :obj:`rand_pos`, :obj:`rand_uni` .. py:function:: rand_ket(d, sparse=False, stype='csr', density=0.01, dtype=complex) Generates a ket of length `d` with normally distributed entries. .. py:function:: rand_uni(d, dtype=complex) Generate a random unitary operator of size `d`, distributed according to the Haar measure. .. seealso:: :obj:`rand_matrix`, :obj:`rand_herm`, :obj:`rand_pos`, :obj:`rand_rho` .. py:function:: rand_haar_state(d, dtype=complex) Generate a random state of dimension `d` according to the Haar distribution. .. py:function:: gen_rand_haar_states(d, reps, dtype=complex) Generate many random Haar states, recycling a random unitary operator by using all of its columns (not a good idea?). .. py:function:: rand_mix(d, tr_d_min=None, tr_d_max=None, mode='rand', dtype=complex) Constructs a random mixed state by tracing out a random ket where the composite system varies in size between 2 and d. This produces a spread of states including more purity but has no real meaning. .. py:function:: rand_product_state(n, qtype=None, dtype=complex) Generates a ket of `n` many random pure qubits. .. py:function:: rand_matrix_product_state(n, bond_dim, phys_dim=2, dtype=complex, cyclic=False, trans_invar=False) Generate a random matrix product state (in dense form, see :func:`~quimb.tensor.MPS_rand_state` for tensor network form). :param n: Number of sites. :type n: int :param bond_dim: Dimension of the bond (virtual) indices. :type bond_dim: int :param phys_dim: Physical dimension of each local site, defaults to 2 (qubits). :type phys_dim: int, optional :param cyclic: Whether to impose cyclic boundary conditions on the entanglement structure. :type cyclic: bool (optional) :param trans_invar: Whether to generate a translationally invariant state, requires cyclic=True. :type trans_invar: bool (optional) :returns: **ket** -- The random state, with shape (phys_dim**n, 1) :rtype: qarray .. py:data:: rand_mps .. py:function:: rand_seperable(dims, num_mix=10, dtype=complex) Generate a random, mixed, seperable state. E.g rand_seperable([2, 2]) for a mixed two qubit state with no entanglement. :param dims: The local dimensions across which to be seperable. :type dims: tuple of int :param num_mix: How many individual product states to sum together, each with random weight. :type num_mix: int, optional :returns: Mixed seperable state. :rtype: qarray .. py:function:: rand_iso(n, m, dtype=complex) Generate a random isometry of shape ``(n, m)``. .. py:function:: rand_mera(n, invariant=False, dtype=complex) Generate a random mera state of ``n`` qubits, which must be a power of 2. This uses ``quimb.tensor``. .. py:function:: seed_rand(seed) See the random number generators, by instantiating a new set of bit generators with a 'seed sequence'. .. py:function:: set_rand_bitgen(bitgen) Set the core bit generator type to use, from either ``numpy`` or ``randomgen``. :param bitgen: Which bit generator to use. :type bitgen: {'PCG64', 'SFC64', 'MT19937', 'Philox', str} .. py:function:: fidelity(p1, p2, squared=False) Fidelity between two quantum states. By default, the unsquared fidelity is used, equivalent in the pure state case to ``||``. :param p1: First state. :type p1: vector or operator :param p2: Second state. :type p2: vector or operator :param squared: Whether to use the squared convention or not, by default False. :type squared: bool, optional :rtype: float .. py:function:: purify(rho) Take state rho and purify it into a wavefunction of squared dimension. :param rho: Density operator to purify. :type rho: operator :returns: The purified ket. :rtype: vector .. py:function:: entropy(a, rank=None) Compute the (von Neumann) entropy. :param a: Positive operator or list of positive eigenvalues. :type a: operator or 1d array :param rank: If operator has known rank, then a partial decomposition can be used to accelerate the calculation. :type rank: int (optional) :returns: The von Neumann entropy. :rtype: float .. seealso:: :obj:`mutinf`, :obj:`entropy_subsys`, :obj:`entropy_subsys_approx` .. py:data:: entropy_subsys Calculate the entropy of a pure states' subsystem, optionally switching to an approximate lanczos method when the subsystem is very large. :param psi_ab: Bipartite state. :type psi_ab: vector :param dims: The sub-dimensions of the state. :type dims: sequence of int :param sysa: The indices of which dimensions to calculate the entropy for. :type sysa: sequence of int :param approx_thresh: The size of sysa at which to switch to the approx method. Set to ``None`` to never use the approximation. :type approx_thresh: int, optional :param \*\*approx_opts: Supplied to :func:`entropy_subsys_approx`, if used. :returns: The subsytem entropy. :rtype: float .. seealso:: :obj:`entropy`, :obj:`entropy_subsys_approx`, :obj:`mutinf_subsys` .. py:data:: mutual_information .. py:function:: mutinf(p, dims=(2, 2), sysa=0, rank=None) Find the mutual information for a bipartition of a state. That is, ``H(A) + H(B) - H(AB)``, for von Neumann entropy ``H``, and two subsystems A and B. :param p: State, can be vector or operator. :type p: vector or operator :param dims: Internal dimensions of state. :type dims: tuple(int), optional :param sysa: Index of first subsystem, A. :type sysa: int, optional :param sysb: Index of second subsystem, B. :type sysb: int, optional :param rank: If known, the rank of rho_ab, to speed calculation of ``H(AB)`` up. For example, if ``p`` comes from tracing out three qubits from a system, then its rank is 2^3 = 8 etc. :type rank: int, optional :rtype: float .. seealso:: :obj:`entropy`, :obj:`mutinf_subsys`, :obj:`entropy_subsys_approx` .. py:function:: mutinf_subsys(psi_abc, dims, sysa, sysb, approx_thresh=2**13, **approx_opts) Calculate the mutual information of two subsystems of a pure state, possibly using an approximate lanczos method for large subsytems. :param psi_abc: Tri-partite pure state. :type psi_abc: vector :param dims: The sub dimensions of the state. :type dims: sequence of int :param sysa: The index(es) of the subsystem(s) to consider part of 'A'. :type sysa: sequence of int :param sysb: The index(es) of the subsystem(s) to consider part of 'B'. :type sysb: sequence of int :param approx_thresh: The size of subsystem at which to switch to the approximate lanczos method. Set to ``None`` to never use the approximation. :type approx_thresh: int, optional :param approx_opts: Supplied to :func:`entropy_subsys_approx`, if used. :returns: The mutual information. :rtype: float .. seealso:: :obj:`mutinf`, :obj:`entropy_subsys`, :obj:`entropy_subsys_approx`, :obj:`logneg_subsys` .. py:function:: schmidt_gap(psi_ab, dims, sysa) Find the schmidt gap of the bipartition of ``psi_ab``. That is, the difference between the two largest eigenvalues of the reduced density operator. :param psi_ab: Bipartite state. :type psi_ab: vector :param dims: The sub-dimensions of the state. :type dims: sequence of int :param sysa: The indices of which dimensions to calculate the entropy for. :type sysa: sequence of int :rtype: float .. py:function:: tr_sqrt(A, rank=None) Return the trace of the sqrt of a positive semidefinite operator. .. py:data:: tr_sqrt_subsys Compute the trace sqrt of a subsystem, possibly using an approximate lanczos method when the subsytem is big. :param psi_ab: Bipartite state. :type psi_ab: vector :param dims: The sub-dimensions of the state. :type dims: sequence of int :param sysa: The indices of which dimensions to calculate the trace sqrt for. :type sysa: sequence of int :param approx_thresh: The size of sysa at which to switch to the approx method. Set to ``None`` to never use the approximation. :type approx_thresh: int, optional :param \*\*approx_opts: Supplied to :func:`tr_sqrt_subsys_approx`, if used. :returns: The subsytem entropy. :rtype: float .. seealso:: :obj:`tr_sqrt`, :obj:`tr_sqrt_subsys_approx`, :obj:`partial_transpose_norm` .. py:function:: partial_transpose(p, dims=(2, 2), sysa=0) Partial transpose of a density operator. :param p: The state to partially transpose. :type p: operator or vector :param dims: The internal dimensions of the state. :type dims: tuple(int), optional :param sysa: The indices of 'system A', everything else assumed to be 'system B'. :type sysa: sequence of int :rtype: operator .. seealso:: :obj:`logneg`, :obj:`negativity` .. py:function:: negativity(p, dims=(2, 2), sysa=0) Compute negativity between two subsytems. This is defined as (| rho_{AB}^{T_B} | - 1) / 2. If ``len(dims) > 2``, then the non-target dimensions will be traced out first. :param p: State to compute logarithmic negativity for. :type p: ket vector or density operator :param dims: The internal dimensions of ``p``. :type dims: tuple(int), optional :param sysa: Index of the first subsystem, A, relative to ``dims``. :type sysa: int, optional :rtype: float .. seealso:: :obj:`logneg`, :obj:`partial_transpose`, :obj:`negativity_subsys_approx` .. py:data:: logarithmic_negativity .. py:function:: logneg(p, dims=(2, 2), sysa=0) Compute logarithmic negativity between two subsytems. This is defined as log_2( | rho_{AB}^{T_B} | ). This only handles bipartitions (including pure states efficiently), and will not trace anything out. :param p: State to compute logarithmic negativity for. :type p: ket vector or density operator :param dims: The internal dimensions of ``p``. :type dims: tuple(int), optional :param sysa: Index of the first subsystem, A, relative to ``dims``. :type sysa: int, optional :rtype: float .. seealso:: :obj:`negativity`, :obj:`partial_transpose`, :obj:`logneg_subsys_approx` .. py:function:: logneg_subsys(psi_abc, dims, sysa, sysb, approx_thresh=2**13, **approx_opts) Compute the logarithmic negativity between two subsystems of a pure state, possibly using an approximate lanczos for large subsystems. Uses a special method if the two subsystems form a bipartition of the state. :param psi_abc: Tri-partite pure state. :type psi_abc: vector :param dims: The sub dimensions of the state. :type dims: sequence of int :param sysa: The index(es) of the subsystem(s) to consider part of 'A'. :type sysa: sequence of int :param sysb: The index(es) of the subsystem(s) to consider part of 'B'. :type sysb: sequence of int :param approx_thresh: The size of subsystem at which to switch to the approximate lanczos method. Set to ``None`` to never use the approximation. :type approx_thresh: int, optional :param approx_opts: Supplied to :func:`~quimb.logneg_subsys_approx`, if used. :returns: The logarithmic negativity. :rtype: float .. seealso:: :obj:`logneg`, :obj:`mutinf_subsys`, :obj:`logneg_subsys_approx` .. py:function:: concurrence(p, dims=(2, 2), sysa=0, sysb=1) Concurrence of two-qubit state. If ``len(dims) > 2``, then the non-target dimensions will be traced out first. :param p: State to compute concurrence for. :type p: ket vector or density operator :param dims: The internal dimensions of ``p``. :type dims: tuple(int), optional :param sysa: Index of the first subsystem, A, relative to ``dims``. :type sysa: int, optional :param sysb: Index of the first subsystem, B, relative to ``dims``. :type sysb: int, optional :rtype: float .. py:function:: one_way_classical_information(p_ab, prjs, precomp_func=False) One way classical information for two qubit density operator. :param p_ab: State of two qubits :type p_ab: operator :param prjs: The POVMs. :type prjs: sequence of matrices :param precomp_func: Whether to return a pre-computed function, closed over the actual state. :type precomp_func: bool, optional :returns: The one-way classical information or the function to compute it for the given state which takes a set of POVMs as its single argument. :rtype: float or callable .. py:function:: quantum_discord(p, dims=(2, 2), sysa=0, sysb=1, method='COBYLA', tol=1e-12, maxiter=2**14) Quantum Discord for two qubit density operator. If ``len(dims) > 2``, then the non-target dimensions will be traced out first. :param p: State to compute quantum discord for. :type p: ket vector or density operator :param dims: The internal dimensions of ``p``. :type dims: tuple(int), optional :param sysa: Index of the first subsystem, A, relative to ``dims``. :type sysa: int, optional :param sysb: Index of the first subsystem, B, relative to ``dims``. :type sysb: int, optional :rtype: float .. py:function:: trace_distance(p1, p2) Trace distance between two states: .. math:: \delta(\rho, \sigma) = \frac{1}{2} \left| \rho - \sigma \right|_\mathrm{tr} If two wavefunctions are supplied the trace distance will be computed via the more efficient expression: .. math:: \delta(|\psi\rangle\langle\psi|, |\phi\rangle\langle\phi|) = \sqrt{1 - \langle \psi | \phi \rangle^2} :param p1: The first state. :type p1: ket or density operator :param p2: The second state. :type p2: ket or density operator :rtype: float .. py:function:: cprint(psi, prec=6) Print a state in the computational basis. :param psi: The pure state. :type psi: vector :param prec: How many significant figures to print. :type prec: int, optional .. rubric:: Examples >>> cprint(rand_ket(2**2)) (-0.0751069-0.192635j) |00> (0.156837-0.562213j) |01> (-0.307381+0.0291168j) |10> (-0.14302+0.707661j) |11> >>> cprint(w_state(4)) (0.5+0j) |0001> (0.5+0j) |0010> (0.5+0j) |0100> (0.5+0j) |1000> .. py:function:: decomp(a, fn, fn_args, fn_d, nmlz_func, mode='p', tol=0.001) Decomposes an operator via the Hilbert-schmidt inner product. Can both print the decomposition or return it. :param a: Operator to decompose. :type a: ket or density operator :param fn: Function to generate operator/state to decompose with. :type fn: callable :param fn_args: Sequence of args whose permutations will be supplied to ``fn``. :param fn_d: The dimension of the operators that `fn` produces. :type fn_d: int :param nmlz_func: Function to produce a normlization coefficient given the ``n`` permutations of operators that will be produced. :type nmlz_func: callable :param mode: String, include ``'p'`` to print the decomp and/or ``'c'`` to return OrderedDict, sorted by size of contribution. :param tol: Print operators with contirbution above ``tol`` only. :returns: Pauli operator name and expec with ``a``. :rtype: None or OrderedDict .. seealso:: :obj:`pauli_decomp`, :obj:`bell_decomp` .. py:data:: pauli_decomp Decompose an operator into Paulis. .. py:data:: bell_decomp Decompose an operator into bell-states. .. py:function:: correlation(p, A, B, sysa, sysb, dims=None, sparse=None, precomp_func=False) Calculate the correlation between two sites given two operators. :param p: State to compute correlations for, ignored if ``precomp_func=True``. :type p: ket or density operator :param A: Operator to act on first subsystem. :type A: operator :param B: Operator to act on second subsystem. :type B: operator :param sysa: Index of first subsystem. :type sysa: int :param sysb: Index of second subsystem. :type sysb: int :param dims: Internal dimensions of ``p``, will be assumed to be qubits if not given. :type dims: tuple of int, optional :param sparse: Whether to compute with sparse operators. :type sparse: bool, optional :param precomp_func: Whether to return result or single arg function closed over precomputed operator. :type precomp_func: bool, optional :returns: The correlation, - , or a function to compute for an arbitrary state. :rtype: float or callable .. py:function:: pauli_correlations(p, ss=('xx', 'yy', 'zz'), sysa=0, sysb=1, sum_abs=False, precomp_func=False) Calculate the correlation between sites for a list of operator pairs choisen from the pauli matrices. :param p: State to compute correlations for. Ignored if ``precomp_func=True``. :type p: ket or density operator :param ss: List of pairs specifiying pauli matrices. :type ss: tuple or str :param sysa: Index of first site. :type sysa: int, optional :param sysb: Index of second site. :type sysb: int, optional :param sum_abs: Whether to sum over the absolute values of each correlation :type sum_abs: bool, optional :param precomp_func: whether to return the values or a single argument function closed over precomputed operators etc. :type precomp_func: bool, optional :returns: Either the value(s) of each correlation or the function(s) to compute the correlations for an arbitrary state, depending on ``sum_abs`` and ``precomp_func``. :rtype: list of float, list of callable, float or callable .. py:function:: ent_cross_matrix(p, sz_blc=1, ent_fn=logneg, calc_self_ent=True, upscale=False) Calculate the pair-wise function ent_fn between all sites or blocks of a state. :param p: State. :type p: ket or density operator :param sz_blc: Size of the blocks to partition the state into. If the number of individual sites is not a multiple of this then the final (smaller) block will be ignored. :type sz_blc: int :param ent_fn: Bipartite function, notionally entanglement :type ent_fn: callable :param calc_self_ent: Whether to calculate the function for each site alone, purified. If the whole state is pure then this is the entanglement with the whole remaining system. :type calc_self_ent: bool :param upscale: Whether, if sz_blc != 1, to upscale the results so that the output array is the same size as if it was. :type upscale: bool, optional :returns: array of pairwise ent_fn results. :rtype: 2D-array .. py:function:: qid(p, dims, inds, precomp_func=False, sparse_comp=True, norm_func=norm, power=2, coeff=1) .. py:function:: is_degenerate(op, tol=1e-12) Check if operator has any degenerate eigenvalues, determined relative to mean spacing of all eigenvalues. :param op: Operator or assumed eigenvalues to check degeneracy for. :type op: operator or 1d-array :param tol: How much closer than evenly spaced the eigenvalue gap has to be to count as degenerate. :type tol: float :returns: **n_dgen** -- Number of degenerate eigenvalues. :rtype: int .. py:function:: is_eigenvector(x, A, tol=1e-14) Determines whether a vector is an eigenvector of an operator. :param x: Vector to check. :type x: vector :param A: Matrix to check. :type A: operator :param tol: The variance must be smaller than this value. :type tol: float, optional :returns: Whether ``A @ x = l * x`` for some scalar ``l``. :rtype: bool .. py:function:: page_entropy(sz_subsys, sz_total) Calculate the page entropy, i.e. expected entropy for a subsytem of a random state in Hilbert space. :param sz_subsys: Dimension of subsystem. :type sz_subsys: int :param sz_total: Dimension of total system. :type sz_total: int :returns: **s** -- Entropy in bits. :rtype: float .. py:function:: heisenberg_energy(L) Get the analytic isotropic heisenberg chain ground energy for length L. Useful for testing. Assumes the heisenberg model is defined with spin operators not pauli matrices (overall factor of 2 smaller). Taken from [1]. [1] Nickel, Bernie. "Scaling corrections to the ground state energy of the spin-½ isotropic anti-ferromagnetic Heisenberg chain." Journal of Physics Communications 1.5 (2017): 055021 :param L: The length of the chain. :type L: int :returns: **energy** -- The ground state energy. :rtype: float .. py:function:: dephase(rho, p, rand_rank=None) Dephase ``rho`` by amount ``p``, that is, mix it with the maximally mixed state: rho -> (1 - p) * rho + p * I / d :param rho: The state. :type rho: operator :param p: The final proportion of identity. :type p: float :param rand_rank: If given, dephase with a random diagonal operator with this many non-zero entries. If float, proportion of full size. :type rand_rank: int or float, optional :returns: **rho_dephase** -- The dephased density operator. :rtype: operator .. py:function:: kraus_op(rho, Ek, dims=None, where=None, check=False) Operate on a mixed state with a set of kraus operators: .. math:: \sigma = \sum_k E_k \rho E_k^{\dagger} :param rho: The density operator to perform operation on. :type rho: (d, d) density matrix :param Ek: The Kraus operator(s). :type Ek: (K, d, d) array or sequence of K (d, d) arrays :param dims: The subdimensions of ``rho``. :type dims: sequence of int, optional :param where: Which of the subsystems to apply the operation on. :type where: int or sequence of int, optional :param check: Where to check ``sum_k(Ek.H @ Ek) == 1``. :type check: bool, optional :returns: **sigma** -- The state after the kraus operation. :rtype: density matrix .. rubric:: Examples The depolarising channel: .. code-block:: python3 In [1]: import quimb as qu In [2]: rho = qu.rand_rho(2) In [3]: I, X, Y, Z = (qu.pauli(s) for s in 'IXYZ') In [4]: [qu.expec(rho, A) for A in (X, Y, Z)] Out[4]: [-0.652176185230622, -0.1301762132792484, 0.22362918368272583] In [5]: p = 0.1 In [6]: Ek = [ ...: (1 - p)**0.5 * I, ...: (p / 3)**0.5 * X, ...: (p / 3)**0.5 * Y, ...: (p / 3)**0.5 * Z ...: ] In [7]: sigma = qu.kraus_op(rho, Ek) In [8]: [qu.expec(sigma, A) for A in (X, Y, Z)] Out[8]: [-0.5652193605332058, -0.11281938484201527, 0.1938119591916957] .. py:function:: projector(A, eigenvalue=1.0, tol=1e-12, autoblock=False) Compute the projector for the target ``eigenvalue`` of operator ``A``. :param A: The hermitian observable. If a tuple is supplied, assume this is the eigendecomposition of the observable. :type A: operator or tuple[array, operator]. :param eigenvalue: The target eigenvalue to construct the projector for, default: 1. :type eigenvalue: float, optional :param tol: The tolerance with which to select all eigenvalues. :type tol: float, optional :param autoblock: Whether to use automatic symmetry exploitation. :type autoblock: bool, optional :returns: **P** -- The projector onto the target eigenspace. :rtype: dense matrix .. py:function:: measure(p, A, eigenvalue=None, tol=1e-12) Measure state ``p`` with observable ``A``, collapsing the state in the process and returning the relevant eigenvalue. .. math:: \left| \psi \right\rangle \rightarrow \frac{ P_i \left| \psi \right\rangle }{ \sqrt{\left\langle \psi \right| P_i \left| \psi \right\rangle} } and .. math:: \rho \rightarrow \frac{ P_i \rho P_i^{\dagger} }{ \text{Tr} \left[ P_i \rho \right] } along with the corresponding eigenvalue :math:`\lambda_i`. :param p: The quantum state to measure. :type p: vector or matrix :param A: The hermitian operator corresponding to an observable. You can supply also a pre-diagonalized operator here as a tuple of eigenvalues and eigenvectors. :type A: matrix or tuple[array, matrix] :param tol: The tolerance within which to group eigenspaces. :type tol: float, optional :param eigenvalue: If specified, deterministically collapse to this result. Otherwise randomly choose a result as in 'real-life'. :type eigenvalue: float, optional :returns: * **result** (*float*) -- The result of the measurement. * **p_after** (*vector or matrix*) -- The quantum state post measurement. .. py:function:: simulate_counts(p, C, phys_dim=2, seed=None) Simulate measuring each qubit of ``p`` in the computational basis, producing output like that of ``qiskit``. :param p: The quantum state, assumed to be normalized, as either a ket or density operator. :type p: vector or operator :param C: The number of counts to perform. :type C: int :param phys_dim: The assumed size of the subsystems of ``p``, defaults to 2 for qubits. :type phys_dim: int, optional :returns: **results** -- The counts for each bit string measured. :rtype: dict[str, int] .. rubric:: Examples Simulate measuring the state of each qubit in a GHZ-state: .. code:: python3 >>> import quimb as qu >>> psi = qu.ghz_state(3) >>> qu.simulate_counts(psi, 1024) {'000': 514, '111': 510} .. py:class:: Evolution(p0, ham, t0=0, compute=None, int_stop=None, method='integrate', int_small_step=False, expm_backend='AUTO', expm_opts=None, progbar=False) Bases: :py:obj:`object` A class for evolving quantum systems according to Schrodinger equation. The evolution can be performed in a number of ways: - diagonalise the Hamiltonian (or use already diagonalised system). - integrate the complex ODE, that is, the Schrodinger equation, using scipy. Here either a mid- or high-order Dormand-Prince adaptive time stepping scheme is used (see :class:`scipy.integrate.complex_ode`). :param p0: Inital state, either vector or operator. If vector, converted to ket. :type p0: quantum state :param ham: Governing Hamiltonian, if tuple then assumed to contain ``(eigvals, eigvecs)`` of presolved system. If callable (but not a SciPy ``LinearOperator``), assume a time-dependent hamiltonian such that ``ham(t)`` is the Hamiltonian at time ``t``. In this case, the latest call to ``ham`` will be cached (and made immutable) in case it is needed by callbacks passed to ``compute``. :type ham: operator, tuple (1d array, operator), or callable :param t0: Initial time (i.e. time of state ``p0``), defaults to zero. :type t0: float, optional :param compute: Function(s) to compute on the state at each time step. Function(s) should take args (t, pt) or (t, pt, ham) if the Hamiltonian is required. If ham is required, it will be passed in to the function exactly as given to this ``Evolution`` instance, except if ``method`` is ``'solve'``, in which case it will be passed in as the solved system ``(eigvals, eigvecs)``. If supplied with: - single callable : ``Evolution.results`` will contain the results as a list, - dict of callables : ``Evolution.results`` will contain the results as a dict of lists with corresponding keys to those given in ``compute``. :type compute: callable, or dict of callable, optional :param int_stop: A condition to terminate the integration early if ``method`` is ``'integrate'``. This callable is called at every successful integration step and should take args (t, pt) or (t, pt, ham) similar to the function(s) in the ``compute`` argument. It should return ``-1`` to stop the integration, otherwise it should return ``None`` or ``0``. :type int_stop: callable, optional :param method: How to evolve the system: - ``'integrate'``: use definite integration. Get system at each time step, only need action of Hamiltonian on state. Generally efficient. - ``'solve'``: diagonalise dense hamiltonian. Best for small systems and allows arbitrary time steps without loss of precision. - ``'expm'``: compute the evolved state using the action of the operator exponential in a 'single shot' style. Only needs action of Hamiltonian, for very large systems can use distributed MPI. :type method: {'integrate', 'solve', 'expm'} :param int_small_step: If ``method='integrate'``, whether to use a low or high order integrator to give naturally small or large steps. :type int_small_step: bool, optional :param expm_backend: How to perform the expm_multiply function if ``method='expm'``. Can further specifiy ``'slepc-krylov'``, or ``'slepc-expokit'``. :type expm_backend: {'auto', 'scipy', 'slepc'} :param expm_opts: Supplied to :func:`~quimb.linalg.base_linalg.expm_multiply` function if ``method='expm'``. :type expm_opts: dict :param progbar: Whether to show a progress bar when calling ``at_times`` or integrating with the ``update_to`` method. :type progbar: bool, optional .. py:attribute:: _p0 .. py:attribute:: _isdop .. py:attribute:: _d .. py:attribute:: _progbar .. py:attribute:: _timedep .. py:attribute:: _method .. py:method:: _setup_callback(fn, int_stop) Setup callbacks in the correct place to compute into _results .. py:method:: _setup_solved_ham() Solve the hamiltonian if needed and find the initial state in the energy eigenbasis for quick evolution later. .. py:method:: _start_integrator(ham, small_step) Initialize a stepping integrator. .. py:method:: _update_to_expm_ket(t) Update the simulation to time ``t``, without explicitly computing the operator exponential itself. .. py:method:: _update_to_solved_ket(t) Update simulation consisting of a solved hamiltonian and a wavefunction to time `t`. .. py:method:: _update_to_solved_dop(t) Update simulation consisting of a solved hamiltonian and a density operator to time `t`. .. py:method:: _update_to_integrate(t) Update simulation consisting of unsolved hamiltonian. .. py:method:: update_to(t) Update the simulation to time ``t`` using relevant method. :param t: Time to update the evolution to. :type t: float .. py:method:: at_times(ts) Generator expression to yield state af list of times. :param ts: Times at which to evolve to, then yield the state. :type ts: sequence of floats :Yields: **pt** (*quantum state*) -- Quantum state of evolution at next time in ``ts``. .. rubric:: Notes If integrating, currently any compute callbacks will be called at every *integration* step, not just the times `ts` -- i.e. in general len(Evolution.results) != len(ts) and if the adaptive step times are needed they should be added as a callback, e.g. ``compute['t'] = lambda t, _: return t``. .. py:property:: t Current time of simulation. :type: float .. py:property:: pt State of the system at the current time (t). :type: quantum state .. py:property:: results Results of the compute callback(s) for each time step. :type: list, or dict of lists, optional .. py:function:: approx_spectral_function(A, f, tol=0.01, *, bsz=1, R=1024, R_min=3, tol_scale=1, tau=0.0001, k_min=10, k_max=512, beta_tol=1e-06, mpi=False, mean_p=0.7, mean_s=1.0, pos=False, v0=None, verbosity=0, single_precision='AUTO', info=None, progbar=False, plot=False, **lanczos_opts) Approximate a spectral function, that is, the quantity ``Tr(f(A))``. :param A: Operator to approximate spectral function for. Should implement ``A.dot(vec)``. :type A: dense array, sparse matrix or LinearOperator :param f: Scalar function with which to act on approximate eigenvalues. :type f: callable :param tol: Relative convergence tolerance threshold for error on mean of repeats. This can pretty much be relied on as the overall accuracy. See also ``tol_scale`` and ``tau``. Default: 1%. :type tol: float, optional :param bsz: Number of simultenous vector columns to use at once, 1 equating to the standard lanczos method. If ``bsz > 1`` then ``A`` must implement matrix-matrix multiplication. This is a more performant way of essentially increasing ``R``, at the cost of more memory. Default: 1. :type bsz: int, optional :param R: The number of repeats with different initial random vectors to perform. Increasing this should increase accuracy as ``sqrt(R)``. Cost of algorithm thus scales linearly with ``R``. If ``tol`` is non-zero, this is the maximum number of repeats. :type R: int, optional :param R_min: The minimum number of repeats to perform. Default: 3. :type R_min: int, optional :param tau: The relative tolerance required for a single lanczos run to converge. This needs to be small enough that each estimate with a single random vector produces an unbiased sample of the operators spectrum.. :type tau: float, optional :param k_min: The minimum size of the krylov subspace to form for each sample. :type k_min: int, optional :param k_max: The maximum size of the kyrlov space to form. Cost of algorithm scales linearly with ``K``. If ``tau`` is non-zero, this is the maximum size matrix to form. :type k_max: int, optional :param tol_scale: This sets the overall expected scale of each estimate, so that an absolute tolerance can be used for values near zero. Default: 1. :type tol_scale: float, optional :param beta_tol: The 'breakdown' tolerance. If the next beta ceofficient in the lanczos matrix is less that this, implying that the full non-null space has been found, terminate early. Default: 1e-6. :type beta_tol: float, optional :param mpi: Whether to parallelize repeat runs over MPI processes. :type mpi: bool, optional :param mean_p: Factor for robustly finding mean and err of repeat estimates, see :func:`ext_per_trim`. :type mean_p: float, optional :param mean_s: Factor for robustly finding mean and err of repeat estimates, see :func:`ext_per_trim`. :type mean_s: float, optional :param v0: Initial vector to iterate with, sets ``R=1`` if given. If callable, the function to produce a random intial vector (sequence). :type v0: vector, or callable :param pos: If True, make sure any approximate eigenvalues are positive by clipping below 0. :type pos: bool, optional :param verbosity: How much information to print while computing. :type verbosity: {0, 1, 2}, optional :param single_precision: Try and convert the operator to single precision. This can lead to much faster operation, especially if a GPU is available. Additionally, double precision is not really needed given the stochastic nature of the algorithm. :type single_precision: {'AUTO', False, True}, optional :param lanczos_opts: Supplied to :func:`~quimb.linalg.approx_spectral.single_random_estimate` or :func:`~quimb.linalg.approx_spectral.construct_lanczos_tridiag`. :returns: The approximate value ``Tr(f(a))``. :rtype: scalar .. seealso:: :obj:`construct_lanczos_tridiag` .. py:function:: tr_abs_approx(*args, **kwargs) .. py:function:: tr_exp_approx(*args, **kwargs) .. py:function:: tr_sqrt_approx(*args, **kwargs) .. py:function:: tr_xlogx_approx(*args, **kwargs) .. py:function:: entropy_subsys_approx(psi_ab, dims, sysa, backend=None, **kwargs) Approximate the (Von Neumann) entropy of a pure state's subsystem. :param psi_ab: Bipartite state to partially trace and find entopy of. :type psi_ab: ket :param dims: The sub dimensions of ``psi_ab``. :type dims: sequence of int, optional :param sysa: Index(es) of the 'a' subsystem(s) to keep. :type sysa: int or sequence of int, optional :param kwargs: Supplied to :func:`approx_spectral_function`. .. py:function:: logneg_subsys_approx(psi_abc, dims, sysa, sysb, **kwargs) Estimate the logarithmic negativity of a pure state's subsystem. :param psi_abc: Pure tripartite state, for which estimate the entanglement between 'a' and 'b'. :type psi_abc: ket :param dims: The sub dimensions of ``psi_abc``. :type dims: sequence of int :param sysa: Index(es) of the 'a' subsystem(s) to keep, with respect to all the dimensions, ``dims``, (i.e. pre-partial trace). :type sysa: int or sequence of int, optional :param sysa: Index(es) of the 'b' subsystem(s) to keep, with respect to all the dimensions, ``dims``, (i.e. pre-partial trace). :type sysa: int or sequence of int, optional :param kwargs: Supplied to :func:`approx_spectral_function`. .. py:function:: negativity_subsys_approx(psi_abc, dims, sysa, sysb, **kwargs) Estimate the negativity of a pure state's subsystem. :param psi_abc: Pure tripartite state, for which estimate the entanglement between 'a' and 'b'. :type psi_abc: ket :param dims: The sub dimensions of ``psi_abc``. :type dims: sequence of int :param sysa: Index(es) of the 'a' subsystem(s) to keep, with respect to all the dimensions, ``dims``, (i.e. pre-partial trace). :type sysa: int or sequence of int, optional :param sysa: Index(es) of the 'b' subsystem(s) to keep, with respect to all the dimensions, ``dims``, (i.e. pre-partial trace). :type sysa: int or sequence of int, optional :param kwargs: Supplied to :func:`approx_spectral_function`. .. py:function:: xlogx(x) .. py:function:: save_to_disk(obj, fname, **dump_opts) Save an object to disk using joblib.dump. .. py:function:: load_from_disk(fname, **load_opts) Load an object form disk using joblib.load. .. py:class:: oset(it=()) An ordered set which stores elements as the keys of dict (ordered as of python 3.6). 'A few times' slower than using a set directly for small sizes, but makes everything deterministic. .. py:attribute:: __slots__ :value: ('_d',) .. py:attribute:: _d .. py:method:: _from_dict(d) :classmethod: .. py:method:: from_dict(d) :classmethod: Public method makes sure to copy incoming dictionary. .. py:method:: copy() .. py:method:: __deepcopy__(memo) .. py:method:: add(k) .. py:method:: discard(k) .. py:method:: remove(k) .. py:method:: clear() .. py:method:: update(*others) .. py:method:: union(*others) .. py:method:: intersection_update(*others) .. py:method:: intersection(*others) .. py:method:: difference_update(*others) .. py:method:: difference(*others) .. py:method:: popleft() .. py:method:: popright() .. py:attribute:: pop .. py:method:: __eq__(other) .. py:method:: __or__(other) .. py:method:: __ior__(other) .. py:method:: __and__(other) .. py:method:: __iand__(other) .. py:method:: __sub__(other) .. py:method:: __isub__(other) .. py:method:: __len__() .. py:method:: __iter__() .. py:method:: __contains__(x) .. py:method:: __repr__() .. py:class:: LRU(maxsize, *args, **kwds) Bases: :py:obj:`collections.OrderedDict` Least recently used dict, which evicts old items. Taken from python collections OrderedDict docs. .. py:attribute:: maxsize .. py:method:: __getitem__(key) x.__getitem__(y) <==> x[y] .. py:method:: __setitem__(key, value) Set self[key] to value. .. py:function:: tree_map(f, tree, is_leaf=is_not_container) Map ``f`` over all leaves in ``tree``, returning a new pytree. :param f: A function to apply to all leaves in ``tree``. :type f: callable :param tree: A nested sequence of tuples, lists, dicts and other objects. :type tree: pytree :param is_leaf: A function to determine if an object is a leaf, ``f`` is only applied to objects for which ``is_leaf(x)`` returns ``True``. :type is_leaf: callable :rtype: pytree .. py:function:: tree_apply(f, tree, is_leaf=is_not_container) Apply ``f`` to all leaves in ``tree``, no new pytree is built. :param f: A function to apply to all leaves in ``tree``. :type f: callable :param tree: A nested sequence of tuples, lists, dicts and other objects. :type tree: pytree :param is_leaf: A function to determine if an object is a leaf, ``f`` is only applied to objects for which ``is_leaf(x)`` returns ``True``. :type is_leaf: callable .. py:function:: tree_flatten(tree, get_ref=False, is_leaf=is_not_container) Flatten ``tree`` into a list of leaves. :param tree: A nested sequence of tuples, lists, dicts and other objects. :type tree: pytree :param is_leaf: A function to determine if an object is a leaf, only objects for which ``is_leaf(x)`` returns ``True`` are returned in the flattened list. :type is_leaf: callable :returns: * **objs** (*list*) -- The flattened list of leaf objects. * **(ref_tree)** (*pytree*) -- If ``get_ref`` is ``True``, a reference tree, with leaves of type ``Leaf``, is returned which can be used to reconstruct the original tree. .. py:function:: tree_unflatten(objs, tree, is_leaf=is_leaf_object) Unflatten ``objs`` into a pytree of the same structure as ``tree``. :param objs: A sequence of objects to be unflattened into a pytree. :type objs: sequence :param tree: A nested sequence of tuples, lists, dicts and other objects, the objs will be inserted into a new pytree of the same structure. :type tree: pytree :param is_leaf: A function to determine if an object is a leaf, only objects for which ``is_leaf(x)`` returns ``True`` will have the next item from ``objs`` inserted. By default checks for the ``Leaf`` object inserted by ``tree_flatten(..., get_ref=True)``. :type is_leaf: callable :rtype: pytree .. py:function:: format_number_with_error(x, err) Given ``x`` with error ``err``, format a string showing the relevant digits of ``x`` with two significant digits of the error bracketed, and overall exponent if necessary. :param x: The value to print. :type x: float :param err: The error on ``x``. :type err: float :rtype: str .. rubric:: Examples >>> print_number_with_uncertainty(0.1542412, 0.0626653) '0.154(63)' >>> print_number_with_uncertainty(-128124123097, 6424) '-1.281241231(64)e+11' .. py:data:: NEUTRAL_STYLE .. py:function:: default_to_neutral_style(fn) Wrap a function or method to use the neutral style by default.