quimb.operator.builder ====================== .. py:module:: quimb.operator.builder .. autoapi-nested-parse:: Given a single definition of hilbert space and set of terms, build out various representations of the operator. This includes: - Sparse matrix in various formats (CSR, CSC, COO, etc.) - Dense matrix - Matrix product operator (MPO) for DMRG etc. - Dict of k-local terms (for use with PEPS etc.) - Coupling function, for use with VMC etc. Attributes ---------- .. autoapisummary:: quimb.operator.builder._OPMAP quimb.operator.builder._OPCOMPLEX Classes ------- .. autoapisummary:: quimb.operator.builder.SparseOperatorBuilder Functions --------- .. autoapisummary:: quimb.operator.builder.get_mat quimb.operator.builder._identity_fn quimb.operator.builder.jordan_wigner_transform quimb.operator.builder.simplify_single_site_ops quimb.operator.builder.simplify quimb.operator.builder.get_pauli_decomp quimb.operator.builder.pauli_decompose quimb.operator.builder.get_pool_and_world_size quimb.operator.builder.build_coupling_numba quimb.operator.builder.calc_dtype_cached Module Contents --------------- .. py:data:: _OPMAP .. py:data:: _OPCOMPLEX .. py:function:: get_mat(op, dtype=None) .. py:function:: _identity_fn(x) .. py:function:: jordan_wigner_transform(terms, site_to_reg=None, reg_to_site=None) Transform the terms in this operator by pre-prending pauli Z strings to all creation and annihilation operators. This is always applied directly to the raw terms, so that the any fermionic ordering is respected. Any further transformations (e.g. simplification or pauli decomposition) should thus be applied after this transformation. Note this doesn't decompose +, - into (X + iY) / 2 and (X - iY) / 2, it just prepends Z strings. Call `pauli_decompose` after this to get the full decomposition. The placement of the Z strings is defined by the ordering supplied by `site_to_reg` and `reg_to_site`, by default, it assumes the terms already are specified on a linear range of integers. :param terms: The terms of the operator. Each term is a tuple of tuples, where each inner tuple is a pair of ``(operator, site)``. :type terms: dict[term, coeff] :param site_to_reg: A function that maps a site to a linear register index. If not provided, the sites are assumed to be linear integers already. :type site_to_reg: callable, optional :param reg_to_site: A function that maps a linear register index to a site. If not provided, the sites are assumed to be linear integers already. :type reg_to_site: callable, optional :returns: **terms_jordan_wigner** -- The transformed terms of the operator. Each term is a tuple of tuples, where each inner tuple is a pair of ``(operator, site)``. :rtype: dict[term, coeff] .. py:function:: simplify_single_site_ops(coeff, ops) Simplify a sequence of operators acting on the same site. :param coeff: The coefficient of the operator sequence. :type coeff: float or complex :param ops: The operator sequence. :type ops: tuple of str :returns: * **new_coeff** (*float or complex*) -- The simplified coefficient. * **new_op** (*str*) -- The single, simplified operator that the sequence maps to, up to scalar multiplication. .. rubric:: Examples >>> simplify_single_site_ops(1.0, ('+', 'z', 'z', 'z', 'z', '-')) (1.0, 'n') >>> simplify_single_site_ops(1.0, ("x", "y", "z")) (-1j, 'I') .. py:function:: simplify(terms, atol=1e-12, site_to_reg=None) Simplify the given terms by combining operators acting on the same site, putting them in canonical order, removing null-terms, and combining equivalent operator strings. :param terms: The terms of the operator. Each term is a tuple of tuples, where each inner tuple is a pair of ``(operator, site)``. :type terms: dict[term, coeff] :param atol: The absolute tolerance for considering coefficients after simplification to be null. :type atol: float, optional :param site_to_reg: A function that maps a site to a linear register index. If not provided, the sites are assumed to be linear integers already. This is just used to sort the operators into canonical order. :type site_to_reg: callable, optional :returns: **terms_simplified** -- The simplified terms of the operator. Each term is a tuple of tuples, where each inner tuple is a pair of ``(operator, site)``. :rtype: dict[term, coeff] .. py:function:: get_pauli_decomp(op, atol=1e-12, use_zx=False) Decompose the given operator (specified as a label) into a sum of Pauli components. :param op: The operator to decompose. :type op: str :param atol: The absolute tolerance for considering coefficients to be null. :type atol: float, optional :param use_zx: Whether to decompose in terms of the real `โดต = ZX = iY` instead of `Y`. :type use_zx: bool, optional :returns: The decomposition of the operator into Pauli components. Each tuple contains the coefficient and the Pauli operator label. :rtype: list[tuple[float, str]] .. py:function:: pauli_decompose(terms, atol=1e-12, use_zx=False, site_to_reg=None) Decompose the given terms into a sum of Pauli strings. :param terms: The terms of the operator. Each term is a tuple of tuples, where each inner tuple is a pair of ``(operator, site)``. :type terms: dict[term, coeff] :param atol: The absolute tolerance for considering coefficients after decomposition to be null. :type atol: float, optional :param use_xz: Whether to decompose in terms of the real `โดต = ZX = iY` instead of `Y`. :type use_xz: bool, optional :param site_to_reg: A function that maps a site to a linear register index. If not provided, the sites are assumed to be linear integers already. This is just used to sort the operators into canonical order. :type site_to_reg: callable, optional :returns: **terms_pauli_decomposed** -- The decomposed terms of the operator. Each term is a tuple of tuples, where each inner tuple is a pair of ``(operator, site)``. :rtype: dict[term, coeff] .. py:function:: get_pool_and_world_size(parallel) .. py:function:: build_coupling_numba(term_store, site_to_reg, dtype=None) Create a sparse nested dictionary of how each term couples each local site configuration to which other local site configuration, and with what coefficient, suitable for use with numba. :param term_store: The terms of the operator. :type term_store: dict[term, coeff] :param site_to_reg: A function that maps a site to a linear register index. :type site_to_reg: callable :returns: **coupling_map** -- The operator defined as tuple of flat arrays. :rtype: tuple[ndarray] .. py:function:: calc_dtype_cached(dtype, iscomplex) .. py:class:: SparseOperatorBuilder(terms=(), hilbert_space: quimb.operator.hilbertspace.HilbertSpace = None, dtype=None, jordan_wigner=False, pauli_decompose=False, atol=1e-12) Object for building operators with sparse structure. Specifically, a sum of terms, where each term is a product of operators, where each of these local operators acts on a single site and has at most one entry per row. :param terms: The terms to initialize the builder with. ``add_term`` is simply called on each of these. :type terms: sequence, optional :param hilbert_space: The Hilbert space to build the operator in. If this is not supplied then a minimal Hilbert space will be constructed from the sites used, when required. The default symmetry and sector to build operators in is inherited from this Hilbert space, but can be overridden. :type hilbert_space: HilbertSpace :param dtype: A default data type for the coefficients of the operator. If not provided, will be automatically determined at building time based on the terms in the operator. If the operator is complex, will be set to ``np.complex128``. If the operator is real, will be set to ``np.float64``. Individual building methods can override this. :type dtype: numpy.dtype or str, optional :param jordan_wigner: Whether to apply the Jordan-Wigner transformation to the terms automatically when processing them. This prepends pauli Z strings to all creation and annihilation operators. :type jordan_wigner: bool, optional :param pauli_decompose: Whether to apply the Pauli decomposition to the terms automatically when processing them. This decomposes all local operators into sums of Pauli operators. If "zx" is supplied, the decomposition is done in terms of the real `ZX = iY` operator instead of `Y`. :type pauli_decompose: bool or "zx", optional :param atol: The absolute tolerance for considering coefficients to be null when simplifying and decomposing terms. :type atol: float, optional .. py:attribute:: _sites_used .. py:attribute:: _hilbert_space :value: None .. py:attribute:: _terms_raw .. py:attribute:: _terms_final :value: None .. py:attribute:: _transform_jordan_wigner :value: False .. py:attribute:: _transform_pauli_decompose :value: False .. py:attribute:: _atol :value: 1e-12 .. py:attribute:: _dtype :value: None .. py:attribute:: _coupling_maps .. py:attribute:: _cache .. py:property:: sites_used A tuple of the sorted coordinates/sites seen so far. .. py:property:: hilbert_space :type: quimb.operator.hilbertspace.HilbertSpace The Hilbert space of the operator. Created from the sites seen so far if not supplied at construction. .. py:property:: nsites The total number of coordinates/sites seen so far. .. py:method:: site_to_reg(site) Get the register / linear index of coordinate ``site``. .. py:method:: reg_to_site(reg) Get the site of register / linear index ``reg``. .. py:property:: terms_raw A tuple of the raw terms seen so far, as a mapping from operator strings to coefficients. .. py:method:: _reset_caches() Reset any cached representations of the operator, used whenever the terms are modified in any way, and thus require reprocessing. .. py:method:: _get_terms_final() Get the processed terms, applying any requested transformations, if not already done. .. py:property:: terms A tuple of the, possibly transformed, terms seen so far. .. py:property:: nterms The total number of terms seen so far. .. py:property:: locality The locality of the operator, the maximum support of any term. .. py:property:: iscomplex Whether the operator has complex terms. .. py:method:: add_term(*coeff_ops) Add a term to the operator. :param coeff: The overall coefficient of the term. :type coeff: float, optional :param ops: The operators of the term, together with the sites they act on. Each term should be a pair of ``(operator, site)``, where ``operator`` can be: - ``'x'``, ``'y'``, ``'z'``: Pauli matrices - ``'sx'``, ``'sy'``, ``'sz'``: spin operators (i.e. scaled Pauli matrices) - ``'+'``, ``'-'``: creation/annihilation operators - ``'n'``, ``'sn'``, or ``'h'``: number, symmetric number (n - 1/2) and hole (1 - n) operators. And ``site`` is a hashable object that represents the site that the operator acts on. If this builder has an associated Hilbert space already, the site must be present in that Hilbert space, else a minimal Hilbert space will be constructed from the sites used, when required. :type ops: sequence of tuple[str, hashable] .. py:method:: __iadd__(term) .. py:method:: __isub__(term) .. py:method:: jordan_wigner_transform(value=None) Toggle transforming the terms in this operator by pre-prending pauli Z strings to all creation and annihilation operators. This is always applied directly as the first processing step to the raw terms, so that the fermionic ordering is respected. Note this doesn't decompose +, - into (X + iY) / 2 and (X - iY) / 2, it just prepends Z strings. Use `pauli_decompose` to get the full decomposition. The placement of the Z strings is defined by the ordering of the hilbert space, by default, the sorted order of the site labels. :param value: Whether to apply the Jordan-Wigner transformation. If `None` (the default) then this method acts as toggle. Whereas supplying `True` or `False` explicitly sets or unsets the transformation. :type value: bool, optional .. py:method:: pauli_decompose(value=None, atol=None, use_zx=False) Transform the terms in this operator by decomposing them into Pauli strings. :param value: Whether to apply the Pauli decomposition. If `None` (the default) then this method acts as toggle. Whereas supplying `True` or `False` explicitly sets or unsets the transformation. :type value: bool, optional .. py:method:: show(filler='.') Print an ascii representation of the terms in this operator. .. py:method:: get_dtype(dtype=None) Calculate the numpy data type of the operator to use. :param dtype: The data type of the coefficients. If not provided, will be automatically determined based on the terms in the operator. :type dtype: numpy.dtype or str, optional :returns: **dtype** -- The data type of the coefficients. :rtype: numpy.dtype .. py:method:: get_coupling_map(dtype=None) Build and cache the coupling map for the specified dtype. :param dtype: The data type of the coefficients. If not provided, will be automatically determined based on the terms in the operator. :type dtype: numpy.dtype, optional :returns: **coupling_map** -- The operator defined as tuple of flat arrays. :rtype: tuple[ndarray] .. py:method:: flatconfig_coupling(flatconfig, dtype=None) Get an array of other configurations coupled to the given individual ``flatconfig`` by this operator, and the corresponding coupling coefficients. This is for use with VMC for example. :param flatconfig: The linear array of the configuration to get the coupling for. :type flatconfig: array[np.uint8] :param dtype: The data type of the matrix. If not provided, will be automatically determined based on the terms in the operator. :type dtype: numpy.dtype, optional :returns: * **coupled_flatconfigs** (*ndarray[np.uint8]*) -- Each distinct flatconfig coupled to ``flatconfig``. * **coeffs** (*ndarray[dtype]*) -- The corresponding coupling coefficients. .. py:method:: config_coupling(config, dtype=None) Get a list of other configurations coupled to ``config`` by this operator, and the corresponding coupling coefficients. This is for use with VMC for example. :param config: The configuration to get the coupling for. :type config: dict[site, int] :returns: * **coupled_configs** (*list[dict[site, np.uint8]]*) -- Each distinct configuration coupled to ``config``. * **coeffs** (*list[dtype]*) -- The corresponding coupling coefficients. .. py:method:: evaluate_exact_flatconfigs(fn_amplitude, progbar=False) Calculate the expectation value of this operator with respect to a wavefunction provided as a function with signature:: fn_amplitude(flatconfig: ndarray[np.uint8]) -> z: float | complex .. py:method:: evaluate_exact_configs(fn_amplitude, progbar=False) Calculate the expectation value of this operator with respect to a wavefunction provided as a function with signature:: fn_amplitude(config: dict[site, int]) -> z: float | complex .. py:method:: build_coo_data(sector=None, symmetry=None, dtype=None, parallel=False) Build the raw data for a sparse matrix in COO format, optionally in parallel. :param sector: The sector of the Hilbert space. If None, the default sector is used. :type sector: {None, str, int, ((int, int), (int, int))}, optional :param symmetry: The symmetry of the Hilbert space. If None, the default symmetry is used, or inferred from the supplied sector if possible. :type symmetry: {None, "Z2", "U1", "U1U1"}, optional :param dtype: The data type of the matrix. If not provided, will be automatically determined based on the terms in the operator. :type dtype: numpy.dtype, optional :param parallel: Whether to build the matrix in parallel (multi-threaded). If True, will use number of threads equal to the number of available CPU cores. If False, will use a single thread. If an integer is provided, it will be used as the number of threads to use. :type parallel: bool or int, optional :returns: * **data** (*array*) -- The data entries for the sparse matrix in COO format. * **rows** (*array*) -- The row indices for the sparse matrix in COO format. * **cols** (*array*) -- The column indices for the sparse matrix in COO format. * **d** (*int*) -- The total number of basis states. .. py:method:: build_sparse_matrix(sector=None, symmetry=None, dtype=None, stype='csr', parallel=False) Build a sparse matrix in the given format. Optionally in parallel. :param sector: The sector of the Hilbert space. If None, the default sector is used. :type sector: {None, str, int, ((int, int), (int, int))}, optional :param symmetry: The symmetry of the Hilbert space. If None, the default symmetry is used, or inferred from the supplied sector if possible. :type symmetry: {None, "Z2", "U1", "U1U1"}, optional :param dtype: The data type of the matrix. If not provided, will be automatically determined based on the terms in the operator. :type dtype: numpy.dtype, optional :param stype: The sparse matrix format to use. Can be one of 'coo', 'csr', 'csc', 'bsr', 'lil', 'dok', or 'dia'. Default is 'csr'. :type stype: str, optional :param parallel: Whether to build the matrix in parallel (multi-threaded). :type parallel: bool, optional :rtype: scipy.sparse matrix .. py:method:: build_dense(sector=None, symmetry=None, dtype=None, parallel=False) Get the dense (`numpy.ndarray`) matrix representation of this operator. :param sector: The sector of the Hilbert space. If None, the default sector is used. :type sector: {None, str, int, ((int, int), (int, int))}, optional :param symmetry: The symmetry of the Hilbert space. If None, the default symmetry is used, or inferred from the supplied sector if possible. :type symmetry: {None, "Z2", "U1", "U1U1"}, optional :param dtype: The data type of the matrix. If not provided, will be automatically determined based on the terms in the operator. :type dtype: numpy.dtype, optional :param parallel: Whether to build the matrix in parallel (multi-threaded). If True, will use number of threads equal to the number of available CPU cores. If False, will use a single thread. If an integer is provided, it will be used as the number of threads to use. :type parallel: bool or int, optional :returns: **A** -- The dense matrix representation of this operator. :rtype: numpy.ndarray .. py:method:: matvec(x, out=None, sector=None, symmetry=None, dtype=None, parallel=False) Apply this operator lazily (i.e. without constructing a sparse matrix) to a vector. This uses less memory but is much slower. :param x: The vector to apply the operator to. :type x: array :param out: An array to store the result in. If not provided, a new array will be created. :type out: array, optional :param sector: The sector of the Hilbert space. If None, the default sector is used. The implicit size should match that of `x`. :type sector: {None, str, int, ((int, int), (int, int))}, optional :param symmetry: The symmetry of the Hilbert space. If None, the default symmetry is used, or inferred from the supplied sector if possible. :type symmetry: {None, "Z2", "U1", "U1U1"}, optional :param dtype: The data type of the matrix. If not provided, will be automatically set as the same as the input vector. :type dtype: numpy.dtype, optional :param parallel: Whether to apply the operator in parallel (multi-threaded). If True, will use number of threads equal to the number of available CPU cores. If False, will use a single thread. If an integer is provided, it will be used as the number of threads to use. Uses `num_threads` more memory but is faster. :type parallel: bool or int, optional :returns: **out** -- The result of applying the operator to the vector. :rtype: array .. py:method:: aslinearoperator(sector=None, symmetry=None, dtype=None, parallel=False) Get a `scipy.sparse.linalg.LinearOperator` for this operator. This is a lazy representation of the operator, which uses `matvec` to apply the operator to a vector. Less memory is required than constructing the full sparse matrix, but it is significantly slower. Note currently the operator is assumed to be hermitian. :param sector: The sector of the Hilbert space. If None, the default sector is used. :type sector: {None, str, int, ((int, int), (int, int))}, optional :param symmetry: The symmetry of the Hilbert space. If None, the default symmetry is used, or inferred from the supplied sector if possible. :type symmetry: {None, "Z2", "U1", "U1U1"}, optional :param dtype: The data type of the matrix. If not provided, will be automatically determined based on the terms in the operator. :type dtype: numpy.dtype, optional :param parallel: Whether to apply the operator in parallel (multi-threaded). If True, will use number of threads equal to the number of available CPU cores. If False, will use a single thread. If an integer is provided, it will be used as the number of threads to use. Uses `num_threads` more memory but is faster. :type parallel: bool or int, optional :returns: **Alo** -- The linear operator representation of this operator. :rtype: scipy.sparse.linalg.LinearOperator .. py:method:: build_local_terms(dtype=None) Get a dictionary of local terms, where each key is a sorted tuple of sites, and each value is the local matrix representation of the operator on those sites. For use with e.g. tensor network algorithms. Note terms acting on the same sites are summed together and the size of each local matrix is exponential in the locality of that term. :returns: **Hk** -- The local terms. :rtype: dict[tuple[hashable], numpy.ndarray] .. py:method:: build_local_ham(dtype=None) Get a `LocalHamGen` object for this operator. :param dtype: The data type of the matrix. If not provided, will be automatically determined based on the terms in the operator. :type dtype: numpy.dtype, optional :returns: **H** -- The local Hamiltonian representation of this operator. :rtype: LocalHamGen .. py:method:: build_state_machine_greedy(atol=1e-12) .. py:method:: draw_state_machine(method='greedy', figsize='auto', G=None) Draw the fintie state machine for this operator, as if buildling the MPO. .. py:method:: build_mpo(method='greedy', dtype=None, **mpo_opts) Build a matrix product operator (MPO) representation of this operator. :param method: The method to use for building the MPO. Currently only "greedy" is supported. :type method: str, optional :param dtype: The data type of the MPO. If not supplied, will be chosen automatically based on the terms in the operator. :type dtype: type, optional :param mpo_opts: Additional options to pass to the MPO constructor. See `MatrixProductOperator` for details. :type mpo_opts: keyword arguments :returns: **mpo** -- The MPO representation of this operator. :rtype: MatrixProductOperator .. py:method:: __repr__() .. py:method:: build_matrix_ikron(**ikron_opts) Build either the dense or sparse matrix of this operator via explicit calls to `ikron`. This is a slower but useful alternative testing method.