def test_jmm1_dictionary(self): """ PIQS: Test the function to generate the mapping from jmm1 to ik matrix. """ d1, d2, d3, d4 = jmm1_dictionary(1) d1_correct = {(0, 0): (0.5, 0.5, 0.5), (0, 1): (0.5, 0.5, -0.5), (1, 0): (0.5, -0.5, 0.5), (1, 1): (0.5, -0.5, -0.5)} d2_correct = {(0.5, -0.5, -0.5): (1, 1), (0.5, -0.5, 0.5): (1, 0), (0.5, 0.5, -0.5): (0, 1), (0.5, 0.5, 0.5): (0, 0)} d3_correct = {0: (0.5, 0.5, 0.5), 1: (0.5, 0.5, -0.5), 2: (0.5, -0.5, 0.5), 3: (0.5, -0.5, -0.5)} d4_correct = {(0.5, -0.5, -0.5): 3, (0.5, -0.5, 0.5): 2, (0.5, 0.5, -0.5): 1, (0.5, 0.5, 0.5): 0} assert_equal(d1, d1_correct) assert_equal(d2, d2_correct) assert_equal(d3, d3_correct) assert_equal(d4, d4_correct) d1, d2, d3, d4 = jmm1_dictionary(2) d1_correct = {(3, 3): (0.0, -0.0, -0.0), (2, 2): (1.0, -1.0, -1.0), (2, 1): (1.0, -1.0, 0.0), (2, 0): (1.0, -1.0, 1.0), (1, 2): (1.0, 0.0, -1.0), (1, 1): (1.0, 0.0, 0.0), (1, 0): (1.0, 0.0, 1.0), (0, 2): (1.0, 1.0, -1.0), (0, 1): (1.0, 1.0, 0.0), (0, 0): (1.0, 1.0, 1.0)} d2_correct = {(0.0, -0.0, -0.0): (3, 3), (1.0, -1.0, -1.0): (2, 2), (1.0, -1.0, 0.0): (2, 1), (1.0, -1.0, 1.0): (2, 0), (1.0, 0.0, -1.0): (1, 2), (1.0, 0.0, 0.0): (1, 1), (1.0, 0.0, 1.0): (1, 0), (1.0, 1.0, -1.0): (0, 2), (1.0, 1.0, 0.0): (0, 1), (1.0, 1.0, 1.0): (0, 0)} d3_correct = {15: (0.0, -0.0, -0.0), 10: (1.0, -1.0, -1.0), 9: (1.0, -1.0, 0.0), 8: (1.0, -1.0, 1.0), 6: (1.0, 0.0, -1.0), 5: (1.0, 0.0, 0.0), 4: (1.0, 0.0, 1.0), 2: (1.0, 1.0, -1.0), 1: (1.0, 1.0, 0.0), 0: (1.0, 1.0, 1.0)} d4_correct = {(0.0, -0.0, -0.0): 15, (1.0, -1.0, -1.0): 10, (1.0, -1.0, 0.0): 9, (1.0, -1.0, 1.0): 8, (1.0, 0.0, -1.0): 6, (1.0, 0.0, 0.0): 5, (1.0, 0.0, 1.0): 4, (1.0, 1.0, -1.0): 2, (1.0, 1.0, 0.0): 1, (1.0, 1.0, 1.0): 0} assert_equal(d1, d1_correct) assert_equal(d2, d2_correct) assert_equal(d3, d3_correct) assert_equal(d4, d4_correct)
def dicke(N, j, m): """ Generate a Dicke state as a pure density matrix in the Dicke basis. For instance, the superradiant state given by :math:`|j, m\\rangle = |1, 0\\rangle` for N = 2, and the state is represented as a density matrix of size (nds, nds) or (4, 4), with the (1, 1) element set to 1. Parameters ---------- N: int The number of two-level systems. j: float The eigenvalue j of the Dicke state (j, m). m: float The eigenvalue m of the Dicke state (j, m). Returns ------- rho: :class: qutip.Qobj The density matrix. """ nds = num_dicke_states(N) rho = np.zeros((nds, nds)) jmm1_dict = jmm1_dictionary(N)[1] i, k = jmm1_dict[(j, m, m)] rho[i, k] = 1. return Qobj(rho)
def dicke_basis(N, jmm1=None): """ Initialize the density matrix of a Dicke state for several (j, m, m1). This function can be used to build arbitrary states in the Dicke basis |j, m><j, m1|. We create coefficients for each (j, m, m1) value in the dictionary jmm1. For instance, if we start from the most excited state for N = 2, we have the following state represented as a density matrix of size (nds, nds) or (4, 4). 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 The mapping for the (i, k) index of the density matrix to the |j, m> values is given by the cythonized function `jmm1_dictionary`. Parameters ---------- N: int The number of two-level systems. jmm1: dict A dictionary of {(j, m, m1): p} that gives a density p for the (j, m, m1) matrix element. Returns ------- rho: :class: qutip.Qobj The density matrix in the Dicke basis. """ if jmm1 is None: msg = "Please specify the jmm1 values as a dictionary" msg += "or use the `excited(N)` function to create an" msg += "excited state where jmm1 = {(N/2, N/2, N/2): 1}" raise AttributeError(msg) nds = _num_dicke_states(N) rho = np.zeros((nds, nds)) jmm1_dict = jmm1_dictionary(N)[1] for key in jmm1: i, k = jmm1_dict[key] rho[i, k] = jmm1[key] return Qobj(rho)
def dicke_basis(N, jmm1=None): """ Initialize the density matrix of a Dicke state for several (j, m, m1). This function can be used to build arbitrary states in the Dicke basis :math:`|j, m\\rangle \\langle j, m^{\\prime}|`. We create coefficients for each (j, m, m1) value in the dictionary jmm1. The mapping for the (i, k) index of the density matrix to the |j, m> values is given by the cythonized function `jmm1_dictionary`. A density matrix is created from the given dictionary of coefficients for each (j, m, m1). Parameters ---------- N: int The number of two-level systems. jmm1: dict A dictionary of {(j, m, m1): p} that gives a density p for the (j, m, m1) matrix element. Returns ------- rho: :class: qutip.Qobj The density matrix in the Dicke basis. """ if jmm1 is None: msg = "Please specify the jmm1 values as a dictionary" msg += "or use the `excited(N)` function to create an" msg += "excited state where jmm1 = {(N/2, N/2, N/2): 1}" raise AttributeError(msg) nds = _num_dicke_states(N) rho = np.zeros((nds, nds)) jmm1_dict = jmm1_dictionary(N)[1] for key in jmm1: i, k = jmm1_dict[key] rho[i, k] = jmm1[key] return Qobj(rho)
def dicke(N, j, m): """ Generate a Dicke state as a pure density matrix in the Dicke basis. For instance, if the superradiant state is given |j, m> = |1, 0> for N = 2, the state is represented as a density matrix of size (nds, nds) or (4, 4), 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 Parameters ---------- N: int The number of two-level systems. j: float The eigenvalue j of the Dicke state |j, m>. m: float The eigenvalue m of the Dicke state |j, m>. Returns ------- rho: :class: qutip.Qobj The density matrix. """ nds = num_dicke_states(N) rho = np.zeros((nds, nds)) jmm1_dict = jmm1_dictionary(N)[1] i, k = jmm1_dict[(j, m, m)] rho[i, k] = 1. return Qobj(rho)
def css(N, x=1 / np.sqrt(2), y=1 / np.sqrt(2), basis="dicke", coordinates="cartesian"): """ Generate the density matrix of the Coherent Spin State (CSS). It can be defined as |CSS>= Prod_i^N(a|1>_i + b|0>_i) with a = sin(theta/2), b = exp(1j*phi) * cos(theta/2). The default basis is that of Dicke space |j, m> < j, m'|. The default state is the symmetric CSS, |CSS> = |+>. Parameters ---------- N: int The number of two-level systems. x, y: float The coefficients of the CSS state. basis: str The basis to use. Either "dicke" or "uncoupled". coordinates: str Either "cartesian" or "polar". If polar then the coefficients are constructed as sin(x/2), cos(x/2)e^(iy). Returns ------- rho: :class: qutip.Qobj The CSS state density matrix. """ if coordinates == "polar": a = np.cos(0.5 * x) * np.exp(1j * y) b = np.sin(0.5 * x) else: a = x b = y if basis == "uncoupled": return _uncoupled_css(N, a, b) nds = num_dicke_states(N) num_ladders = num_dicke_ladders(N) rho = dok_matrix((nds, nds)) # loop in the allowed matrix elements jmm1_dict = jmm1_dictionary(N)[1] j = 0.5 * N mmax = int(2 * j + 1) for i in range(0, mmax): m = j - i psi_m = np.sqrt(float(energy_degeneracy(N, m))) * \ a**(N*0.5 + m) * b**(N*0.5 - m) for i1 in range(0, mmax): m1 = j - i1 row_column = jmm1_dict[(j, m, m1)] psi_m1 = np.sqrt(float(energy_degeneracy(N, m1))) * \ np.conj(a)**(N*0.5 + m1) * np.conj(b)**(N*0.5 - m1) rho[row_column] = psi_m * psi_m1 return Qobj(rho)
def css(N, x=1/np.sqrt(2), y=1/np.sqrt(2), basis="dicke", coordinates="cartesian"): """ Generate the density matrix of the Coherent Spin State (CSS). It can be defined as, :math:`|CSS \\rangle = \\prod_i^N(a|1\\rangle_i + b|0\\rangle_i)` with :math:`a = sin(\\frac{\\theta}{2})`, :math:`b = e^{i \\phi}\\cos(\\frac{\\theta}{2})`. The default basis is that of Dicke space :math:`|j, m\\rangle \\langle j, m'|`. The default state is the symmetric CSS, :math:`|CSS\\rangle = |+\\rangle`. Parameters ---------- N: int The number of two-level systems. x, y: float The coefficients of the CSS state. basis: str The basis to use. Either "dicke" or "uncoupled". coordinates: str Either "cartesian" or "polar". If polar then the coefficients are constructed as sin(x/2), cos(x/2)e^(iy). Returns ------- rho: :class: qutip.Qobj The CSS state density matrix. """ if coordinates == "polar": a = np.cos(0.5 * x) * np.exp(1j * y) b = np.sin(0.5 * x) else: a = x b = y if basis == "uncoupled": return _uncoupled_css(N, a, b) nds = num_dicke_states(N) num_ladders = num_dicke_ladders(N) rho = dok_matrix((nds, nds)) # loop in the allowed matrix elements jmm1_dict = jmm1_dictionary(N)[1] j = 0.5*N mmax = int(2*j + 1) for i in range(0, mmax): m = j-i psi_m = np.sqrt(float(energy_degeneracy(N, m))) * \ a**(N*0.5 + m) * b**(N*0.5 - m) for i1 in range(0, mmax): m1 = j - i1 row_column = jmm1_dict[(j, m, m1)] psi_m1 = np.sqrt(float(energy_degeneracy(N, m1))) * \ np.conj(a)**(N*0.5 + m1) * np.conj(b)**(N*0.5 - m1) rho[row_column] = psi_m*psi_m1 return Qobj(rho)