Source code for entanglish.SymNupState

import itertools as it
import numpy as np
import entanglish.utilities as ut


[docs]class SymNupState: """ This class is designed to perform tasks related to a SymNupState. SymNupState is an abbreviation for Symmetrized N-qubits-up State, which is a special, very convenient for testing purposes, type of quantum state vector. Note, this is a pure state of qubits only. No qudits with d != 2 in this state. The state contains a total of num_qbits qubits. num_up of them are up (in state ``|1>``) and num_qbits - num_up are down (in state ``|0>``). To build such a state, we first create any ( normalized) initial state vector with the required number of up and down qubits, and then we apply a total symmetrizer to that initial state vector. It turns out that SymNupState's have a (bipartite) entanglement that is known and has a simple analytical expression given by the classical entropy of a hyper-geometric distribution. See Ref.1 for a more detailed explanation of the algos used in this class. References ---------- 1. R.R. Tucci, "A New Algorithm for Calculating Squashed Entanglement and a Python Implementation Thereof" Attributes ---------- num_qbits : int total number of qubits in the state num_up : int should be <= num_qbits. The number of qubits that is up (in state ``|1>``). The other num_qbits - n_up are down (in state ``|0>``) """
[docs] def __init__(self, num_up, num_qbits): """ Constructor Parameters ---------- num_up : int num_qbits : int Returns ------- """ assert 0 <= num_up <= num_qbits self.num_qbits = num_qbits self.num_up = num_up
[docs] def get_st_vec(self): """ This method outputs the (pure) state vector for the SymNupState object. Returns ------- np.ndarray shape=(2^self.num_qbits, ) """ st_vec = np.zeros(tuple([2]*self.num_qbits), dtype=complex) all_axes = list(range(0, self.num_qbits)) comb_len = self.num_up for up_axes in it.combinations(all_axes, comb_len): index = tuple([1 if k in up_axes else 0 for k in range(self.num_qbits)]) st_vec[index] = 1 mag = np.linalg.norm(st_vec) st_vec /= mag return st_vec.reshape((1 << self.num_qbits,))
[docs] def get_known_entang(self, num_x_axes): """ This method calculates the (bipartite) entanglement analytically, from a known formula, not numerically. E(x_axes, y_axes)=E(y_axes, x_axes) (order of x_axes and y_axes arguments doesn't matter) len(x_axes)= num_x_axes, and len(y_axes)= num_row_axes - num_x_axes. After the symmetrization of the state, E(x_axes, y_axes) only depends of the numbers of x_axes and y_axes. One can prove that E(x_axes, y_axes) is given by the hyper-geometric distribution (see Ref.1) References ---------- 1. `<https://en.wikipedia.org/wiki/Hypergeometric_distribution)>`_ Parameters ---------- num_x_axes : int Returns ------- float """ assert 0 <= num_x_axes <= self.num_qbits nn = self.num_qbits n = num_x_axes xx = self.num_up probs = [ut.prob_hypergeometric(x, xx, n, nn) for x in range(xx + 1)] return ut.get_entropy_from_probs(np.array(probs))
if __name__ == "__main__": def main(): num_up = 4 num_qbits = 5 st = SymNupState(num_up, num_qbits) print('st_vec=\n', st.get_st_vec()) for num_x_axes in range(0, num_qbits+1): print('known entang for ' + str(num_x_axes) + ' x axes=', st.get_known_entang(num_x_axes)) main()