quimb.core ========== .. py:module:: quimb.core .. autoapi-nested-parse:: Core functions for manipulating quantum objects. Attributes ---------- .. autoapisummary:: quimb.core._NUM_THREAD_WORKERS quimb.core._NUMBA_CACHE quimb.core.njit quimb.core.vectorize quimb.core._numpy_qarray_overrides quimb.core._COMPLEX_DTYPES quimb.core._DOUBLE_DTYPES quimb.core._DTYPE_MAP quimb.core._SPARSE_CONSTRUCTORS quimb.core._EXPEC_METHODS quimb.core.expec quimb.core.normalize_ quimb.core.chop_ quimb.core.qu quimb.core.ket quimb.core.bra quimb.core.dop quimb.core.sparse quimb.core.eye quimb.core.speye quimb.core._dim_mapper_methods quimb.core.nmlz quimb.core.tr quimb.core.ptr Classes ------- .. autoapisummary:: quimb.core.CacheThreadPool quimb.core.qarray Functions --------- .. autoapisummary:: quimb.core.prod quimb.core.get_thread_pool quimb.core.par_reduce quimb.core.make_immutable quimb.core.isclose_qarray quimb.core.ensure_qarray quimb.core.realify_scalar quimb.core.realify quimb.core.zeroify quimb.core.common_type quimb.core.upcast quimb.core.dag quimb.core.isket quimb.core.isbra quimb.core.isop quimb.core.isvec quimb.core.issparse quimb.core.isdense quimb.core.isreal quimb.core.allclose_sparse quimb.core.isherm quimb.core.ispos quimb.core.threading_choose_num_blocks quimb.core.threading_get_block_range quimb.core.maybe_multithread quimb.core._complex_array_numba quimb.core.complex_array quimb.core._phase_to_complex_numba quimb.core.phase_to_complex quimb.core.mul_dense quimb.core.mul quimb.core._subtract_update_2d_numba quimb.core._subtract_update_1d_numba quimb.core.subtract_update_ quimb.core._divide_update_2d_numba quimb.core._divide_update_1d_numba quimb.core.divide_update_ quimb.core._dot_csr_matvec_numba quimb.core.par_dot_csr_matvec quimb.core.dot_sparse quimb.core.dot quimb.core.vdot quimb.core.rdot quimb.core._l_diag_dot_dense_par quimb.core.l_diag_dot_dense quimb.core.l_diag_dot_sparse quimb.core.ldmul quimb.core._r_diag_dot_dense_par quimb.core.r_diag_dot_dense quimb.core.r_diag_dot_sparse quimb.core.rdmul quimb.core._outer_par quimb.core.outer quimb.core.explt quimb.core._kron_dense_numba quimb.core.kron_dense quimb.core.kron_sparse quimb.core.kron_dispatch quimb.core.sparse_matrix quimb.core.expectation quimb.core.normalize quimb.core.chop quimb.core.quimbify quimb.core.infer_size quimb.core._trace_dense quimb.core._trace_sparse quimb.core.trace quimb.core._identity_dense quimb.core._identity_sparse quimb.core.identity quimb.core._kron_core quimb.core.dynal quimb.core.gen_matching_dynal quimb.core.gen_ops_maybe_sliced quimb.core.kron quimb.core.kronpow quimb.core._find_shape_of_nested_int_array quimb.core._dim_map_1d quimb.core._dim_map_1dtrim quimb.core._dim_map_1dcyclic quimb.core._dim_map_2dcyclic quimb.core._dim_map_2dtrim quimb.core._dim_map_2d quimb.core._dim_map_nd quimb.core.dim_map quimb.core._dim_compressor quimb.core.dim_compress quimb.core.ikron quimb.core._permute_dense quimb.core._permute_sparse quimb.core.permute quimb.core.pkron quimb.core.ind_complement quimb.core.itrace quimb.core._partial_trace_dense quimb.core._trace_lose quimb.core._trace_keep quimb.core._partial_trace_simple quimb.core.partial_trace quimb.core.sparse_hermitian_conjugate quimb.core.csr_mulvec_wrap quimb.core.sp_mulvec_wrap Module Contents --------------- .. py:function:: prod(iterable) .. py:data:: _NUM_THREAD_WORKERS .. py:data:: _NUMBA_CACHE .. py:data:: njit Numba no-python jit, but obeying cache setting. .. py:data:: vectorize Numba vectorize, but obeying cache setting. .. py:class:: CacheThreadPool(func) Bases: :py:obj:`object` .. py:attribute:: _settings :value: '__UNINITIALIZED__' .. py:attribute:: _pool_fn .. py:method:: __call__(num_threads=None) .. py:function:: get_thread_pool(num_workers=None) .. py:function:: par_reduce(fn, seq, num_threads=_NUM_THREAD_WORKERS) Parallel reduce. :param fn: Two argument function to reduce with. :type fn: callable :param seq: Sequence to reduce. :type seq: sequence :param num_threads: The number of threads to reduce with in parallel. :type num_threads: int, optional :rtype: depends on ``fn`` and ``seq``. .. rubric:: Notes This has a several hundred microsecond overhead. .. py:function:: make_immutable(mat) Make array read only, in-place. :param mat: Matrix to make immutable. :type mat: sparse or dense array .. py:function:: isclose_qarray(a, b, **kwargs) Check if two qarrays are close. This is a simple wrapper around the base numpy function, but ensures that the arrays are converted to standard numpy arrays first, to avoid a call to the overridden `__and__` method. :param a: First array. :type a: qarray :param b: Second array. :type b: qarray :param rtol: The relative tolerance parameter. :type rtol: array_like :param atol: The absolute tolerance parameter (see Notes). :type atol: array_like :param equal_nan: Whether to compare NaN's as equal. If True, NaN's in a will be considered equal to NaN's in b in the output array. :type equal_nan: bool :rtype: bool .. py:data:: _numpy_qarray_overrides .. 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:: ensure_qarray(fn) Decorator that wraps output as a ``qarray``. .. py:function:: realify_scalar(x, imag_tol=1e-12) .. py:function:: realify(fn, imag_tol=1e-12) Decorator that drops ``fn``'s output imaginary part if very small. .. py:function:: zeroify(fn, tol=1e-14) Decorator that rounds ``fn``'s output to zero if very small. .. py:data:: _COMPLEX_DTYPES .. py:data:: _DOUBLE_DTYPES .. py:data:: _DTYPE_MAP .. py:function:: common_type(*arrays) Quick compute the minimal dtype sufficient for ``arrays``. .. py:function:: upcast(fn) Decorator to make sure the types of two numpy arguments match. .. py:function:: dag(qob) Conjugate transpose. .. 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:: allclose_sparse(A, B, **allclose_opts) .. 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:: threading_choose_num_blocks(size_total, target_block_size, num_threads) Given `size_total` items, `target_block_size`, and number of threads `num_threads`, choose the number of blocks to split `size_total` into, the base block size, and the remainder, used with `threading_get_block_range`. :param size_total: Total number of items to split. :type size_total: int :param target_block_size: Target block size. If positive, blocks will be at least this size. If negative, blocks will be close to this size. :type target_block_size: int :param num_threads: Number of threads to split into. :type num_threads: int :returns: Number of blocks, base block size, and block remainder. :rtype: int, int, int .. py:function:: threading_get_block_range(b, base_block_size, block_remainder) Given block index `b`, base block size `base_block_size`, and remainder `block_remainder`, return the start and stop indices of the block. .. py:function:: maybe_multithread(fn, *args, size_total, target_block_size, num_threads, **kwargs) Based on the size of the problem, either call `fn` directly or get a pool and multithread it. .. py:function:: _complex_array_numba(x, y, out, thread_rank=0, num_threads=1, target_block_size=2**15) .. py:function:: complex_array(x, y, num_threads=None, target_block_size=2**15) Accelerated creation of complex array. .. py:function:: _phase_to_complex_numba(x, out, thread_rank=0, num_threads=1, target_block_size=2**10) .. py:function:: phase_to_complex(x, num_threads=None, target_block_size=2**10) Convert an array of phases to actual complex numbers. .. py:function:: mul_dense(x, y) Numba-accelerated element-wise multiplication of two dense matrices. .. 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:: _subtract_update_2d_numba(X, c, Y, thread_rank=0, num_threads=1, target_block_size=2**14) .. py:function:: _subtract_update_1d_numba(X, c, Y, thread_rank=0, num_threads=1, target_block_size=2**14) .. py:function:: subtract_update_(X, c, Y, num_threads=None, target_block_size=2**14) Accelerated inplace computation of ``X -= c * Y``. This is mainly for Lanczos iteration. .. py:function:: _divide_update_2d_numba(X, c, out, thread_rank=0, num_threads=1, target_block_size=2**14) .. py:function:: _divide_update_1d_numba(X, c, out, thread_rank=0, num_threads=1, target_block_size=2**14) .. py:function:: divide_update_(X, c, out, num_threads=None, target_block_size=2**14) Accelerated computation of ``X / c`` into ``out``. .. py:function:: _dot_csr_matvec_numba(data, indptr, indices, vec, out, thread_rank=0, num_threads=1, target_block_size=-1024) .. py:function:: par_dot_csr_matvec(A, x, target_block_size=-1024, num_threads=None) Parallel sparse csr-matrix vector dot product. :param A: Operator. :type A: scipy.sparse.csr_matrix :param x: Vector. :type x: dense vector :param target_block_size: The target block size (number of rows) for each thread if parallel. :type target_block_size: int, optional :param num_threads: Number of threads to use. If None, will use the default number of threads. :type num_threads: int, optional :returns: Result of ``A @ x``. :rtype: dense vector .. rubric:: Notes The main bottleneck for sparse matrix vector product is memory access, as such this function is only beneficial for pretty large matrices. .. py:function:: dot_sparse(a, b) Dot product for sparse matrix, dispatching to parallel for v large nnz. .. 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:: _l_diag_dot_dense_par(l, A, out, thread_rank=0, num_threads=1, target_block_size=128) .. py:function:: l_diag_dot_dense(diag, mat, num_threads=None, target_block_size=128) Dot product of diagonal matrix (with only diagonal supplied) and dense matrix. .. py:function:: l_diag_dot_sparse(diag, mat) Dot product of digonal matrix (with only diagonal supplied) and sparse matrix. .. 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:: _r_diag_dot_dense_par(A, l, out, thread_rank=0, num_threads=1, target_block_size=128) .. py:function:: r_diag_dot_dense(mat, diag, num_threads=None, target_block_size=128) Dot product of dense matrix and digonal matrix (with only diagonal supplied). .. py:function:: r_diag_dot_sparse(mat, diag) Dot product of sparse matrix and digonal matrix (with only diagonal supplied). .. 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_par(x, y, out, m, n, thread_rank=0, num_threads=1, target_block_size=128) .. py:function:: outer(a, b, num_threads=None, target_block_size=128) Outer product between two vectors (no conjugation). .. py:function:: explt(l, t) Complex exponenital as used in solution to schrodinger equation. .. py:function:: _kron_dense_numba(x, y, out, m, n, p, q, thread_rank=0, num_threads=1, target_block_size=128) .. py:function:: kron_dense(a, b, num_threads=None, target_block_size=128) .. py:function:: kron_sparse(a, b, stype=None) Sparse tensor (kronecker) product, Output format can be specified or will be automatically determined. .. py:function:: kron_dispatch(a, b, stype=None) Kronecker product of two arrays, dispatched based on dense/sparse and also size of product. .. py:data:: _SPARSE_CONSTRUCTORS .. py:function:: sparse_matrix(data, stype='csr', dtype=complex) Construct a sparse matrix of a particular format. :param data: Fed to scipy.sparse constructor. :type data: array_like :param stype: Sparse format. :type stype: {'csr', 'csc', 'coo', 'bsr'}, optional :returns: Of format ``stype``. :rtype: scipy sparse matrix .. py:data:: _EXPEC_METHODS .. 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: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:data:: normalize_ .. 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:data:: chop_ .. 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_dense(op) Trace of a dense operator. .. py:function:: _trace_sparse(op) Trace of a sparse operator. .. 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_dense(d, dtype=complex) Returns a dense, identity of given dimension ``d`` and type ``dtype``. .. py:function:: _identity_sparse(d, stype='csr', dtype=complex) Returns a sparse, complex identity of order d. .. 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:: _kron_core(*ops, stype=None, coo_build=False, parallel=False) Core kronecker product for a sequence of objects. .. py:function:: dynal(x, bases) Generate 'dynamic decimal' for ``x`` given ``dims``. .. rubric:: Examples >>> dims = [13, 2, 7, 3, 10] >>> prod(dims) # total hilbert space size 5460 >>> x = 3279 >>> drep = list(dyn_bin(x, dims)) # dyn bases repr >>> drep [7, 1, 4, 0, 9] >>> bs_szs = [prod(dims[i + 1:]) for i in range(len(dims))] >>> bs_szs [420, 210, 30, 10, 1] >>> # reconstruct x >>> sum(d * b for d, b in zip(drep, bs_szs)) 3279 .. py:function:: gen_matching_dynal(ri, rf, dims) Return the matching dynal part of ``ri`` and ``rf``, plus the first pair that don't match. .. py:function:: gen_ops_maybe_sliced(ops, ix) Take ``ops`` and slice the first few, according to the length of ``ix`` and with ``ix``, and leave the rest. .. 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:: _find_shape_of_nested_int_array(x) Take a n-nested list/tuple of integers and find its array shape. .. py:function:: _dim_map_1d(sza, coos) .. py:function:: _dim_map_1dtrim(sza, coos) .. py:function:: _dim_map_1dcyclic(sza, coos) .. py:function:: _dim_map_2dcyclic(sza, szb, coos) .. py:function:: _dim_map_2dtrim(sza, szb, coos) .. py:function:: _dim_map_2d(sza, szb, coos) .. py:function:: _dim_map_nd(szs, coos, cyclic=False, trim=False) .. py:data:: _dim_mapper_methods .. 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_compressor(dims, inds) Helper function for ``dim_compress`` that does the heavy lifting. :param dims: The subsystem dimensions. :type dims: sequence of int :param inds: The indices of the 'marked' subsystems. :type inds: sequence of int :returns: Sequence of pairs of new dimension subsystem with marked flag {0, 1}. :rtype: generator of (int, int) .. 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:: 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:: :py:obj:`kron`, :py: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:: _permute_dense(p, dims, perm) Permute the subsytems of a dense array. .. py:function:: _permute_sparse(a, dims, perm) Permute the subsytems of a sparse matrix. .. 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:: :py: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:: 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:: :py:obj:`ikron`, :py: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:: ind_complement(inds, n) Return the indices below ``n`` not contained in ``inds``. .. 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:: :py:obj:`trace`, :py: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_dense(p, dims, keep) Perform partial trace of a dense matrix. .. py:function:: _trace_lose(p, dims, lose) Simple partial trace where the single subsytem at ``lose`` is traced out. .. py:function:: _trace_keep(p, dims, keep) Simple partial trace where the single subsytem at ``keep`` is kept. .. py:function:: _partial_trace_simple(p, dims, keep) Simple partial trace made up of consecutive single subsystem partial traces, augmented by 'compressing' the dimensions each time. .. 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:: :py: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:data:: nmlz Alias for :func:`normalize`. .. py:data:: tr Alias for :func:`trace`. .. py:data:: ptr Alias for :func:`partial_trace`. .. py:function:: sparse_hermitian_conjugate(self) .. py:function:: csr_mulvec_wrap(fn) Dispatch sparse csr-vector multiplication to parallel method. .. py:function:: sp_mulvec_wrap(fn) Scipy sparse doesn't call __array_finalize__ so need to explicitly make sure qarray input -> qarray output.