entanglish.DenMat module

class entanglish.DenMat.DenMat(num_rows, row_shape, arr=None)[source]

Bases: object

This class specifies a quantum mechanical Density Matrix. The class also performs a large number of operations on the density matrix self.

Normally, a density matrix is a Hermitian matrix whose eigenvalues define a probability distribution (i.e., the eigenvalues are real numbers between zero and one and they sum to 1.) This class does not automatically check that self is Hermitian, although you can do it yourself with the method is_hermitian(). The class doesn’t check that the trace is one either, although you can do it yourself with the method trace(). It is often useful to use this class to hold an “un-normalized” density matrix whose trace is not 1. So trace=1 is seldom assumed by the functions of this class. On the other hand, many of the functions in this class, especially the ones that involve finding eigenvalues, do assume that self is Hermitian.

The attribute arr holds a numpy array of shape (num_rows, num_rows), where num_rows is also an attribute. Another attribute is row_shape, which is a tuple of integers whose product is num_rows. At any time, arr can be reshaped from (num_rows, num_rows) to row_shape*2.

For example, suppose row_shape = (3, 4, 2). Then this density matrix will be taken to represent a mixed state of 3 qudits with d=3, d=4 and d=2 in that order. When we take a partial trace over the second (d=4) qudit, we contract the second row index with the second column index.

To use this class in conjunction with Qubiter, replace self.arr in this class with the output of Qubiter.StateVec.get_den_mat()

The marginals of self is defined as a list of partial traces of self. The n’th item in the list of marginals is the partial trace of self, traced over all qudits except the n’th. The Kronecker product of the marginals of self is a “separable” density matrix, in the sense that there is no correlation among its qudits.

Variables:
  • arr (np.ndarray) – numpy array of shape (num_rows, num_rows) which contains entries of a density matrix
  • marginals (list[DenMat]) –
  • num_rows (int) –
  • row_shape (tuple[int]) – tuple of integers whose product is num_rows
__add__(right)[source]

Defines ‘+’ between self and another DenMat, the input ‘right’.

Parameters:right (DenMat) –
Returns:
Return type:DenMat
__getitem__(key)[source]

Defines self[int1, int2] to be same as self.arr[int1, int2]

Parameters:key (tuple[int, int]) –
Returns:
Return type:complex
__iadd__(right)[source]

Defines ‘+=’ between self and another DenMat, the input ‘right’.

Parameters:right (DenMat) –
Returns:
Return type:DenMat
__imul__(right)[source]

Defines ‘*=’ as inplace matrix multiplication between self and another DenMat or a scalar (either int, float or complex), the input ‘right’.

Parameters:right (DenMat|complex|float|int) –
Returns:
Return type:DenMat
__init__(num_rows, row_shape, arr=None)[source]

Constructor

Parameters:
  • num_rows (int) –
  • row_shape (tuple[int]) –
  • arr (np.ndarray) – shape=(num_rows, num_rows)
__isub__(right)[source]

Defines ‘-=’ between self and another DenMat, the input ‘right’.

Parameters:right (DenMat) –
Returns:
Return type:DenMat
__mul__(right)[source]

Defines ‘*’ as np.dot() between self and another DenMat or a scalar (either int, float or complex), the input ‘right’. Multiplication by a scalar is defined only if scalar is on the right side of self.

Parameters:right (DenMat|complex|float|int) –
Returns:
Return type:DenMat
__repr__()[source]

Returns str(self.arr).

Returns:
Return type:str
__setitem__(key, item)[source]

Defines assignment self[int1, int2] = item to be same as self.arr[int1, int2] = item.

Parameters:
  • key (tuple[int, int]) –
  • item (complex|float|int) –
Returns:

Return type:

None

__str__()[source]

Returns str(self.arr).

Returns:
Return type:str
__sub__(right)[source]

Defines ‘-‘ between self and another DenMat, the input ‘right’.

Parameters:right (DenMat) –
Returns:
Return type:DenMat
add_const_to_diag_of_arr(const)[source]

Adds constant const to diagonal of self.arr.

Parameters:const (complex|float|int) –
Returns:
Return type:None
add_vec_to_diag_of_arr(vec_arr)[source]

Adds vector vec_arr to diagonal of self.arr

Parameters:vec_arr (np.ndarray) –
Returns:
Return type:None
conj()[source]

This method returns a DenMat which is the complex conjugate of self.

Returns:
Return type:DenMat
copy()[source]

This method returns a copy of self.

Returns:
Return type:DenMat
depurify(eps)[source]

If self is a pure state, this method returns a nearby density mat that is mixed

Parameters:eps (float) – small positive number
Returns:
Return type:DenMat
dm_iop(right, arr_iop)[source]

Internal method used in magic methods __iadd__, __isub__, __imul__, which define in-place binary operations between self and another DenMat.

Parameters:
  • right (DenMat) –
  • arr_iop (wrapper_descriptor) – This is going to be either np.ndarray.[__iadd__, __isub__], np.dot
Returns:

returns self

Return type:

DenMat

dm_op(right, arr_op)[source]

Internal method used in magic methods __add__, __sub__, __mul__, which define binary operations between self and another DenMat.

Parameters:
  • right (DenMat) –
  • arr_op (wrapper_descriptor) – This is going to be either np.ndarray.[__add__, __sub__], np.dot
Returns:

Return type:

DenMat

exp(approx='eigen')[source]

This method returns a DenMat which is the matrix exponential of self.

Parameters:approx (str) – approx used to calculate exp. Either ‘eigen’ or ‘pade’.
Returns:
Return type:DenMat
get_eigen_sys_of_marginals()[source]

eva = eigenvalue, evec = eigenvector, sep = separable.

This method assumes self is Hermitian.

We will call an ‘eigensystem’ of a density matrix: a tuple, whose first item is a 1D numpy array, call it evas, that carries the eigenvalues of the density matrix, and the second item is a 2D numpy array, call it eigen_cols, whose i’th columns is an eigenvector for the i’th eigenvalue (i.e., evas[i]) of the density matrix.

This method returns a tuple of two lists. The first list contains the first part (eigenvalues) of the eigensystem of each marginal of self. The second list contains the second part (eigenvectors) of the eigensystem of each marginal of self.

Returns:
Return type:tuple[list[np.ndarray], list[np.ndarray]]
get_eigenvalue_proj_ops(eps=1e-05)[source]

This method returns a tuple of 2 DenMat that carry Hermitian projection operators:

proj_0 projects out the space of zero (abs < eps) eigenvalues. It is obtained by replacing in the eigen decomposition of self.arr, zero eigenvalues (abs < eps) by 1 and non-zero ones (abs > eps) by 0.

proj_1 projects out the space of non-zero (abs > eps) eigenvalues. It is obtained by replacing in the eigen decomposition of self.arr, zero eigenvalues (abs < eps) by 0 and non-zero ones (abs > eps) by 1.

Parameters:eps (float) – 0 < eps << 1
Returns:
Return type:DenMat, DenMat
get_entropy(approx='eigen')[source]

This method returns an exact entropy of density matrix self. Uses natural log for entropy. Assumes eigenvalues of self are non-negative and sum to 1.

Parameters:approx (str) – approx used to calculate log of array. Either ‘eigen’ or ‘pade’
Returns:
Return type:float
static get_fun_of_dm_from_eigen_sys(num_rows, row_shape, eigen_sys, fun_of_scalars, **fun_kwargs)[source]

If (evas, U) = eigen_sys and fun = fun_of_scalars, then this method returns U.fun(evas).U^dag, where U^dag is the Hermitian conjugate of the unitary matrix U.

The function calculated (for example, np.exp, np.log, etc.) is passed in as the input ‘fun_of_scalars’. To get just an approx to dm instead of an approx to fun of dm, use fun_of_scalars = lambda x: x

Parameters:
  • num_rows (int) –
  • row_shape (tuple[int]) –
  • eigen_sys (tuple[np.ndarray, np.ndarray]) –
  • fun_of_scalars – function that can act on scalars or numpy arrays element-wise
  • fun_kwargs (dict) – dict of keyword args that fun depends on
Returns:

Return type:

DenMat

static get_kron_prod_of_den_mats(den_mat_list)[source]

Takes as input a list of DenMat’s and returns a DenMat which is the Kronecker product of the items in the input list.

Parameters:den_mat_list (list[DenMat]) –
Returns:
Return type:DenMat
get_mutual_info(traced_axes_set, approx='eigen')[source]

This method returns the mutual information for x_axes = list( traced_axes_set) and y_axes = row axes not in x_axes. Uses natural log for entropy. Assumes eigenvalues of self are non-negative and sum to 1.

Parameters:
  • traced_axes_set (set[int]) –
  • approx (str) – approx used to calculate log of array. Either ‘eigen’ or ‘pade’
Returns:

Return type:

float

get_partial_tr(traced_axes_set)[source]

This method returns the partial trace of a density matrix den_mat. It traces over the indices (a.k.a. axes) in the non-empty set traced_axes_set. To get a full trace, just do den_mat.trace()

Parameters:traced_axes_set (set[int]) – Set of axes being traced over
Returns:
Return type:DenMat
get_rho_xy(x_axes, y_axes)[source]

The inputs ‘x_axes’ and ‘y_axes’ must be mutually exclusive lists whose union, after sorting, is range(len(self.row_shape)), which equals [0, 1, 2, …, number of row axes -1]. The output is a DenMat in which the rows (and columns) of self.arr have been permuted to the order x_axes + y_axes.

Parameters:
  • x_axes (list[int]) –
  • y_axes (list[int]) –
Returns:

Return type:

DenMat

get_set_of_all_other_axes(axes_set)[source]

This method returns the complement set wrt range(len(self.row_shape)) of the set of axes axes_set

Parameters:axes_set (set[int]) –
Returns:
Return type:set[int]
herm()[source]

This method returns a DenMat which is the Hermitian conjugate of self.

Returns:
Return type:DenMat
inv(regulator=0.0)[source]

This method returns a DenMat which is the inverse matrix of self.

logs, exponentials and sqrt’s of matrices are calculated by various methods. Inverses of matrices, on the other hand, are calculated a single way.

Parameters:regulator (float) – this constant is added to diagonal of copy of self.arr before taking the inverse of copy
Returns:
Return type:DenMat
is_pure_state()[source]

This method returns a bool which answers the question whether self is a pure state or not.

Returns:
Return type:bool
log(approx='eigen', eps=None, clip_to_zero=False)[source]

This method returns a DenMat which is the matrix natural log of self.

Parameters:
  • approx (str) – approx used to calculate the natural log. Either ‘eigen’ or ‘pade’.
  • eps (float | None) – clips logs larger than log(eps) to log(eps) (or to zero if clip_to_zero=True) if this is a float. Doesn’t clip if this is None
  • clip_to_zero (bool) – clips to zero iff this is True
Returns:

Return type:

DenMat

static new_const_den_mat(num_rows, row_shape, const)[source]

This method returns a DenMat object with an arr which is a diagonal matrix with ‘const’ in its diagonal.

Parameters:
  • num_rows (int) –
  • row_shape (tuple[int]) –
  • const (int|float|complex) –
Returns:

Return type:

DenMat

static new_with_permuted_qudits(dm, perm)[source]

This method returns a DenMat in which the rows (and columns) of dm.arr have been permuted according to perm.

Parameters:
  • dm (DenMat) –
  • perm (list[int}) – perm is a permutation of range(len(self.row_shape))
Returns:

Return type:

DenMat

norm()[source]

This method returns the 2-norm of self.arr

Returns:
Return type:float
normalize_diag_of_arr()[source]

Divides the diagonal of self.arr by the trace of self.arr.

Returns:
Return type:None
normalize_entire_arr()[source]

Divides all of self.arr by the trace of self.arr.

Returns:
Return type:None
positive_part(threshold=1e-05)[source]

This method returns a DenMat in which negative (< 0) eigenvalues of self.arr are replaced by zero.

Returns:
Return type:DenMat
pseudo_inv(eps=1e-05)[source]

This method returns a DenMat which is the Penrose pseudo inverse matrix of self. By pseudo inverse, we mean that it takes the inverse of non-zero (abs > eps) eigenvalues only, but sets those eigenvalues with abs < eps to exactly zero.

Parameters:eps (float) –
Returns:
Return type:DenMat
purer_version()[source]

This method returns a DenMat in which all eigenvalues of self.arr except the maximum one are replaced by zero.

Returns:
Return type:DenMat
purer_version2()[source]

This method returns a DenMat in which self.arr is replaced by ( self.arr^2)/sqrt(tr2) where tr2 is the trace of self.arr^2. This transformation has no effect on self if self is an un-normalized pure state.

Returns:
Return type:DenMat
replace_diag_of_arr(new_diag)[source]

Replaces diagonal of self.arr by new_diag.

Parameters:new_diag (np.ndarray) –
Returns:
Return type:None
set_arr_from_st_vec(st_vec)[source]

Sets self.arr to st_vec*set_vec^dag where st_vec is a column vector of shape (num_rows, ). For qubits, st_vec should be a traditional state vector, meaning that when reshaped to [2]*num_qbits, the components are .. |s_2>|s_1>|s_0> where s_i = 0, 1 corresponds to the i’th qubit. s_0 is last so ZL (Zero Last) convention.

Parameters:st_vec (np.ndarray) – shape=(self.num_rows,)
Returns:
Return type:None
set_arr_to_rand_den_mat(evas)[source]

evas = eigenvalues.

This method sets self.arr to a random density matrix UDU^dag, where U is a random unitary matrix, D is a non-random diagonal matrix with diagonal equal to the input 1D array ‘evas’, and U^dag is the Hermitian conjugate of U. This method checks that evas is a probability distribution. The DenMat returned by this method is useful for testing purposes.

Parameters:evas (np.ndarray) – evas stands for eigenvalues. 1D array of floats, of shape ( self.num_rows, )
Returns:
Return type:None
set_arr_to_zero()[source]

Sets self.arr to zero matrix.

Returns:
Return type:None
set_marginals()[source]

This method calculates the single-axis marginals of self and stores them in self.marginals.

Returns:
Return type:None
sqrt(approx='eigen')[source]

This method returns a DenMat which is the matrix square root of self.

Parameters:approx (str) – approx used to calculate sqrt. Either ‘eigen’ or ‘pade’.
Returns:
Return type:DenMat
switch_arr_basis(umat, reverse=False)[source]

This method returns a new DenMat whose arr is U^dag(self.arr)U (or the reverse, U(self.arr)U^dag, if the input bool parameter ‘reverse’ is set to True.) U = umat , U^dag = Hermitian conjugate of U

Parameters:
  • umat (np.ndarray) –
  • reverse (bool) –
Returns:

Return type:

DenMat

trace()[source]

This method returns the real part of the full trace of self.

Returns:
Return type:float