Source code for qmatchatea.utils.tn_utils

# This code is part of qmatchatea.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""
I/O functions for tensors and mps (list of tensors).
Furthermore, the class :py:class:`QCOperators` for handling operators is provided.

Functions and classes
---------------------

"""

# pylint: disable=too-many-branches

import numpy as np
from qtealeaves import read_tensor
from qtealeaves.operators import TNOperators

__all__ = ["write_tensor", "write_mps", "read_mps", "QCOperators"]


[docs] def write_tensor(tensor, dest, cmplx=True, sparse=False): """ Write a tensor stored in a numpy matrix to a file. Conversion to column major is taken care of here. **Arguments** tensor : np.ndarray Tensor to be written to the file. dest : str, or filehandle If string, file will be created or overwritten. If filehandle, then data will be written there. sparse: bool If True write the tensor in a sparse format, i.e. each row is written as idx elem where idx is the position of the element elem in the tensor vector """ if isinstance(dest, str): # pylint: disable=consider-using-with fh = open(dest, "w+") elif hasattr(dest, "write"): fh = dest else: raise TypeError("`dest` for `write_tensor` neither str nor writeable.") # Number of links fh.write("%d \n" % (len(tensor.shape))) # Dimensions of links dl = " ".join(list(map(str, tensor.shape))) fh.write(dl + "\n") # Now we need to transpose tensor_colmajor = np.reshape(tensor, -1, order="F") if sparse: nonzero = np.nonzero(tensor_colmajor)[0] # index of nonzero element tensor_colmajor = tensor_colmajor[nonzero] nonzero += 1 # from python to fortran indexing fh.write(f"{len(nonzero)} \n") for ii, elem in enumerate(tensor_colmajor): if cmplx: if sparse: fh.write( "%d (%30.15E, %30.15E)\n" % (nonzero[ii], np.real(elem), np.imag(elem)) ) else: fh.write("(%30.15E, %30.15E)\n" % (np.real(elem), np.imag(elem))) else: if sparse: fh.write("%d %30.15E\n" % (nonzero[ii], np.real(elem))) else: fh.write("%30.15E\n" % (np.real(elem))) imag_part = np.imag(elem) if np.abs(imag_part) > 1e-14: raise TypeError("Writing complex valued tensor as real valued tensor.") if isinstance(dest, str): fh.close() return
[docs] def read_mps(filename, cmplx=True): """Read an MPS from a given file. Reads in column-major order but the output is in row-major. This function was used to exchange the MPS with the Fortran backend (thus the different ordering), which is now deprecated. Parameters ---------- filename: str PATH to the file cmplx: bool, optional If True the MPS is complex, real otherwise. Default to True Returns ------- mps: list list of np.array in row-major order """ mps = [] with open(filename, "r") as fh: num_sites = int(fh.readline()) for _ in range(num_sites): tens = read_tensor(fh, cmplx=cmplx) mps.append(tens) return mps
[docs] def write_mps(filename, mps, cmplx=True): """Write an MPS to file. The tensor is written in Fortran-like indexing, i.e. the MPS tensors will be converted from row-major into column-major order. This function was used to exchange the MPS with the Fortran backend (thus the different ordering), which is now deprecated. Parameters ---------- filename: str PATH to the file mps: list List of tensors forming the mps cmplx: bool, optional If True the MPS is complex, real otherwise. Default to True Returns ------- None """ with open(filename, "w") as fh: fh.write(str(len(mps)) + " \n") for tens in mps: write_tensor(tens, fh, cmplx=cmplx) return None
[docs] class QCOperators(TNOperators): """ Class to store and save to file operators. To add an operator to the list use self['op_name'] = op_tensor. It starts with the pauli operators already defined, with keywords "X","Y","Z" """ def __init__(self): TNOperators.__init__(self) pauli_matrices = { "Z": np.array([[1, 0], [0, -1]]), "X": np.array([[0, 1], [1, 0]]), "Y": np.array([[0, -1j], [1j, 0]]), "I": np.array([[1, 0], [0, 1]]), } for key, val in pauli_matrices.items(): self[key] = val