def get_c_op_mats(L, N, depth = None): if depth == None: depth = N single_particle_states = 2*prod(L) c_op_mats = [ None ] * single_particle_states * depth for dd in range(depth): # determine dimensions of input and output hilbert spaces dim_in = int(binomial(single_particle_states, N-dd)) dim_out = int(binomial(single_particle_states, N-dd-1)) for state_num in range(single_particle_states): # initialize zero matrix for an annihilation operator addressing this state matrix = sparse.dok_matrix((dim_out,dim_in), dtype = int) # loop over all states in the input fock space for index_in, states_in in fock_state_basis(L, N-dd): if state_num not in states_in: continue # determine which single particle states are still occupied after # applying the annihilation operator remaining_states = tuple( state for state in states_in if state != state_num ) # determine whether we pick up a sign upon annihilation sign = sum([ 1 for state in states_in if state > state_num ]) % 2 # loop over all states in the output fock space for index_out, states_out in fock_state_basis(L, N-dd-1): if states_out == remaining_states: matrix[index_out, index_in] = (-1)**sign # store the matrix for this annihilation operator c_op_mats[single_particle_states*dd + state_num] = matrix.tocsr() return c_op_mats
def riim_coeffs(n, num_cnots): """Generates coefficients a_n for RIIM extrapolation. Arguments: n: (int) The order of RIIM to be performed. num_cnots: (int) number of CNOTs in the circuit. Returns: (list) A list of RIIM coefficients. """ a3_1 = -1 / 2 a_1 = -num_cnots * a3_1 + 1 a3_2 = -(num_cnots + 4) * (1 / 4) a5_2 = 3 / 8 a33_2 = 1 / 4 a_2 = 1 - num_cnots * a3_2 - num_cnots * a5_2 - binomial(num_cnots, 2) * a33_2 a3_3 = -(num_cnots**2 + 10 * num_cnots + 24) * (1 / 16) a5_3 = (1 / 16) * (3 * (num_cnots + 6)) a33_3 = (num_cnots + 6) * (1 / 8) a7_3 = -5 / 16 a35_3 = -3 / 16 a333_3 = -1 / 8 a_3 = 1 - num_cnots * a3_3 - num_cnots * a5_3 - binomial( num_cnots, 2) * a33_3 - num_cnots * a7_3 - 2 * binomial( num_cnots, 2) * a35_3 - binomial(num_cnots, 3) * a333_3 a3_4 = -(num_cnots**3 + 18 * num_cnots**2 + 104 * num_cnots + 192) * (1 / 96) a5_4 = (3 * num_cnots**2 + 32 * num_cnots + 154) * (1 / 64) a33_4 = (num_cnots**2 + 14 * num_cnots + 58) * (1 / 32) a7_4 = -45 / 32 a35_4 = -(3 * num_cnots + 29) * (1 / 32) a333_4 = -(num_cnots + 8) * (1 / 16) a9_4 = 35 / 128 a55_4 = 29 / 64 a335_4 = 3 / 32 a3333_4 = 1 / 16 a73_4 = 0 a_4 = 1 - num_cnots * a3_4 - num_cnots * a5_4 - num_cnots * a7_4 - num_cnots \ * a9_4 - (binomial(num_cnots, 4) * a3333_4) - (binomial(num_cnots, 3) \ * a333_4) - (3 * binomial(num_cnots, 3) * a335_4) - (binomial( num_cnots, 2) * a33_4) - (2 * binomial(num_cnots, 2) * a35_4) \ - (binomial(num_cnots, 2) * a55_4) coeffs_1 = [a_1, a3_1] coeffs_2 = [a_2, a3_2, a5_2, a33_2] coeffs_3 = [a_3, a3_3, a5_3, a33_3, a7_3, a35_3, a333_3] coeffs_4 = [ a_4, a3_4, a5_4, a33_4, a7_4, a35_4, a333_4, a9_4, a73_4, a55_4, a335_4, a3333_4 ] coeffs = [coeffs_1, coeffs_2, coeffs_3, coeffs_4] return coeffs[n - 1]
def Sxyz(a, b, diffA, diffB, gamma): """Calculate the one dimensional overlap integral over two Gaussian functions divided by sqrt(pi). Returns: overlap of two Gaussian functions Args: a: (int) exponent of the first Cartesian prefactor (x-x_a0)^a b: (int) exponent of the second Cartesian prefactor (x-x_b0)^b diffA: (float) the difference between the center of the combined Gaussian and the center of the first original Gaussian diffB: (float) the difference between the center of the combined Gaussian and the center of the second original Gaussian gamma: (float) the combined exponent """ indices = ( (i, j) for i in range(0, a + 1) for j in range(0, b + 1) if (i + j) % 2 == 0 ) result = sum( ( binomial(a, i) * binomial(b, j) * _dfac(i + j - 1) * pow(diffA, a - i) * pow(diffB, b - j) / pow(2 * gamma, (i + j) * 0.5) for i, j in indices ) ) result /= _sqrt(gamma) return result
def test_binomial(): assert binomial(0, 0) == 1.0 assert binomial(1, 0) == 1.0 assert binomial(2, 0) == 1.0 assert binomial(3, 0) == 1.0 assert binomial(0, 1) == 0.0 assert binomial(0, 2) == 0.0 assert binomial(0, 3) == 0.0 assert binomial(4, 2) == 6.0 assert binomial(10, 3) == 120.0 return None
def generate_spherical_coeff_symb(l, m, lx, ly, lz, unnorm=False): j = (lx + ly - abs(m)) if j % 2 == 0: j = int(j / 2) else: return sympy.Integer(0) j_symb = sympy.Integer(j) l_symb = sympy.Integer(l) m_symb = sympy.Integer(abs(m)) lx_symb = sympy.Integer(lx) ly_symb = sympy.Integer(ly) lz_symb = sympy.Integer(lz) prefactor = symb_fact(2 * lx_symb) * symb_fact(2 * ly_symb) * symb_fact( 2 * lz_symb) * symb_fact(l_symb) prefactor = prefactor * symb_fact(l_symb - m_symb) prefactor = prefactor / (symb_fact(2 * l_symb) * symb_fact(lx_symb) * symb_fact(ly_symb) * symb_fact(lz_symb)) prefactor = prefactor / symb_fact(l_symb + m_symb) # Ed's stupid normalization convention... if unnorm: prefactor = prefactor * symb_fact2(2 * l - 1) / symb_fact2( 2 * lx - 1) / symb_fact2(2 * ly - 1) / symb_fact2(2 * lz - 1) prefactor = sympy.sqrt(prefactor) term1 = sympy.Integer(0) for i in range(int((l - abs(m)) / 2) + 1): term1 = term1 + sympy.Integer(binomial(l,i)) * sympy.Integer(binomial(i,j)) * \ sympy.Integer(math.pow(-1,i)) * symb_fact( 2*l_symb - sympy.Integer(2*i) ) / \ symb_fact( l_symb - m_symb - sympy.Integer(2*i) ) term1 = term1 / (2**l_symb) / symb_fact(l) m_fact_symb = sympy.Integer(1) if m < 0: m_fact_symb = -m_fact_symb term2 = sympy.Integer(0) for k in range(j + 1): z = sympy.exp(m_fact_symb * sympy.pi / 2 * (m_symb - lx_symb + sympy.Integer(2 * k)) * symb_I) term2 = term2 + sympy.Integer(binomial(j, k)) * sympy.Integer( binomial(abs(m), lx - 2 * k)) * z return prefactor * term1 * term2
def polarized_states_FH(L, N): # if we are at (below) unit filling, return a state vector (density operator) if N == prod(L): vec_z = prod([ c_op(q,1) for q in spatial_basis(L) ]).vector(L, N) vec_x = prod([ c_op(q,1) + c_op(q,0) for q in spatial_basis(L) ]).vector(L, N) vec_y = prod([ c_op(q,1) + 1j * c_op(q,0) for q in spatial_basis(L) ]).vector(L, N) vec_z = vec_z / sparse.linalg.norm(vec_z) vec_x = vec_x / sparse.linalg.norm(vec_x) vec_y = vec_y / sparse.linalg.norm(vec_y) return vec_z, vec_x, vec_y hilbert_dim = int(binomial(2*prod(L), N)) state_z = sparse.csr_matrix((hilbert_dim,hilbert_dim), dtype = float) state_x = sparse.csr_matrix((hilbert_dim,hilbert_dim), dtype = float) state_y = sparse.csr_matrix((hilbert_dim,hilbert_dim), dtype = complex) for momenta in itertools.combinations(spatial_basis(L), N): vec_z = prod([ c_op(q,1) for q in momenta ]).vector(L, N) vec_x = prod([ c_op(q,1) + c_op(q,0) for q in momenta ]).vector(L, N) vec_y = prod([ c_op(q,1) + 1j * c_op(q,0) for q in momenta ]).vector(L, N) state_z += vec_z * vec_z.getH() state_x += vec_x * vec_x.getH() state_y += vec_y * vec_y.getH() state_z /= state_z.diagonal().sum() state_x /= state_x.diagonal().sum() state_y /= state_y.diagonal().sum() return state_z, state_x, state_y
def vector(self, L, N): num_ops = len(self.seq) # assert we have the same nubmer of operators as particles assert(N == num_ops) # determine dimension of hilbert space hilbert_dim = int(binomial(2*prod(L), N)) # if we have an empty sequence, return the zero matrix if num_ops == 0: return sparse.csr_matrix((hilbert_dim,1), dtype = int) # assert that all operators are of the same type (i.e. creation / annihilation) assert( len(set( op.creation for op in self.seq )) == 1 ) # sort operators, picking up a sign in the prefactor if necessary self.sort() # determine which sinle-particle states will be occupied occupied_states = tuple( op.index(L) for op in self.seq[::-1] ) # if any operators are repeats, return the zero state if len(occupied_states) != len(set(occupied_states)): return sparse.csr_matrix((hilbert_dim,1), dtype = int) # loop over the fock basis to determine the appropriate vector for index, states in fock_state_basis(L, N): if states == occupied_states: data = [self.prefactor] location = ([index],[0]) return sparse.csr_matrix((data, location), (hilbert_dim,1)) sys.exit("state not found in fock basis...")
def occupations_to_state_number(indices: List[int]) -> int: k = 1 result = 0 for _iter in indices: result += int(binomial(_iter, k)) k += 1 return result
def main(nqubits, num_1): """Creates a superposition circuit that finds all states with num_1 1's in a fixed number of qubits, then the oracle find that state where all the 1's are at the beginning of the bitstring. This oracle has got ancillas Args: nqubits (int): number of qubits num_1 (int): number of 1's to find Returns: solution (str): found string iterations (int): number of iterations needed """ superposition = superposition_circuit(nqubits, num_1) oracle_circuit = oracle(nqubits, num_1) or_circuit = Circuit(oracle_circuit.nqubits) or_circuit.add( oracle_circuit.on_qubits( *(list(range(nqubits)) + [oracle_circuit.nqubits - 1] + list(range(nqubits, oracle_circuit.nqubits - 1))))) grover = Grover(or_circuit, superposition_circuit=superposition, superposition_qubits=nqubits, number_solutions=1, superposition_size=int(binomial(nqubits, num_1))) solution, iterations = grover() print('The solution is', solution) print('Number of iterations needed:', iterations) return solution, iterations
def dicke_projector(L, N, c_op_mats): hilbert_dim = int(binomial(2*prod(L), N)) # collective spin raising operator and its m-th power (initially m = 0) S_p = spin_op_m_FH(L, N, c_op_mats).getH() S_p_m = sparse.eye(hilbert_dim).tocsr() # build projector by looping over all projections m of collective spin onto the z axis projector = sparse.csr_matrix((hilbert_dim,hilbert_dim), dtype = float) for m in range(N+1): norm = 1 / binomial(N, m) for momenta in itertools.combinations(spatial_basis(L), N): vec_m = prod([ c_op(q,0) for q in momenta ]).vector(L,N) vec_m = S_p_m.dot(vec_m) projector += vec_m * vec_m.getH() / (vec_m.getH().dot(vec_m)[0,0]) S_p_m = S_p.dot(S_p_m) return projector
def faulhaber(n, p): """ sum of the p-th powers of the first n positive integers :return: 1^p + 2^p + 3^p + ... + n^p https://en.wikipedia.org/wiki/Faulhaber%27s_formula """ s = 0 for j, a in enumerate(bernouilli_gen()): if j > p: break s = s + binomial(p + 1, j) * a * n**(p + 1 - j) return s // (p + 1)
def state_number_to_occupations(state_number: int, Q: int) -> List[int]: k = Q indices = [] while k > 0: ck = find_maximal_ck(state_number, k) indices.insert(0, ck) state_number -= int(binomial(ck, k)) k -= 1 assert state_number == 0 return indices
def _eval_wignerd(self, j, m, mp, beta): from numpy import pi, sin, cos, sqrt try: from scipy.misc import factorial except ImportError: from scipy.special import factorial from scipy.special import binom as binomial r = 0 if beta == pi / 2: # Varshalovich Equation (5), Section 4.16, page 113, setting # alpha=gamma=0. for k in range(int(2 * j) + 1): if k > j + mp or k > j - m or k < mp - m: continue r += (-1)**k * binomial(j + mp, k) * \ binomial(j - mp, k + m - mp) r *= (-1)**(m - mp) / 2**j * \ sqrt(factorial(j + m) * factorial(j - m) / (factorial(j + mp) * factorial(j - mp))) else: # Varshalovich Equation(5), Section 4.7.2, page 87, where we set # beta1=beta2=pi/2, and we get alpha=gamma=pi/2 and beta=phi+pi, # then we use the Eq. (1), Section 4.4. page 79, to simplify: # d(j, m, mp, beta+pi) = (-1)**(j-mp) * d(j, m, -mp, beta) # This happens to be almost the same as in Eq.(10), Section 4.16, # except that we need to substitute -mp for mp. size, mvals = self._m_values(j) for mpp in mvals: r += self._eval_wignerd(j, m, mpp, pi / 2) * \ (cos(-mpp * beta) + 1j * sin(-mpp * beta)) * \ self._eval_wignerd(j, mpp, -mp, pi / 2) # Empirical normalization factor so results match Varshalovich # Tables 4.3-4.12 # Note that this exact normalization does not follow from the # above equations r = r * 1j**(2 * j - m - mp) * (-1)**(2 * m) return r
def generate_spherical_coeff(l, m, lx, ly, lz): j = (lx + ly - abs(m)) if j % 2 == 0: j = int(j / 2) else: return 0.0 prefactor = fact(2. * lx) * fact(2. * ly) * fact(2. * lz) * fact(l) prefactor = prefactor * fact(l - abs(m)) prefactor = prefactor / (fact(2. * l) * fact(lx) * fact(ly) * fact(lz)) prefactor = prefactor / fact(l + abs(m)) prefactor = math.sqrt(prefactor) term1 = 0.0 for i in range(int((l - abs(m)) / 2) + 1): term1 = term1 + binomial(l,i) * binomial(i,j) * \ math.pow(-1,i) * fact( 2*l - 2*i ) / \ fact( l - abs(m) - 2*i ) term1 = term1 / math.pow(2, l) / fact(l) m_fact = 1. if m < 0: m_fact = -1. term2 = 0.0 + 0.0j for k in range(j + 1): z = cmath.exp(m_fact * math.pi / 2. * (abs(m) - lx + 2 * k) * 1.j) term2 = term2 + binomial(j, k) * binomial(abs(m), lx - 2 * k) * z val = prefactor * term1 * term2 if abs(val.real) < 1e-10: val = 0.0 + val.imag * 1j if abs(val.imag) < 1e-10: val = val.real return val
def distribute_samples(n, subsets_size_range, n_samples): """Distribute samples evenly in a given range. A function that is used in order to distribute evenly, the amount of samples that will be drawn from a range of subset's sizes, from an original set of given size. Parameters ---------- n : int The set size. subsets_size_range : tuple A touple having the min and the max subset size. n_samples : int The number of samples. Returns ------ samples_on_subsets : dict Returns a dictionary of samples, for each subset. """ # Check input min_ss, max_ss = subsets_size_range[0], subsets_size_range[1] # Distribute samples to subset groups maxd = min(max_ss, n) w = np.array([binomial(n, k) for k in range(min_ss, maxd + 1)], dtype=float) w = w / np.sum(w) smpls = np.floor(w * n_samples).astype(int) ss = smpls.shape[0] for r in range(int(n_samples - np.sum(smpls))): smpls[(ss - r - 1) % ss] += 1 return {i + min_ss: smpls[i] for i in range(ss) if smpls[i] > .0}
def S(k): """ Computes the set of possible numbers of true hoypotheses. Parameters: ----------- k: int number of algorithms being compared. Returns ---------- TrueSet : array-like Set of true hypotheses. """ from scipy.special import binom as binomial TrueHset = [0] if k > 1: for j in np.arange(k, 0, -1, dtype=int): TrueHset = list( set(TrueHset) | set([binomial(j, 2) + x for x in S(k - j)])) return TrueHset
def RIIM_coeffs(n, num_cnots): """ Generates coefficients a_n for RIIM extrapolation. :param n: (int) The order of RIIM to be performed. :param num_cnots: (int) number of CNOTs in the circuit. :return: (list) A list of RIIM coefficients """ Nc = num_cnots a3_1 = -1 / 2 a_1 = -Nc * a3_1 + 1 a3_2 = -(Nc + 4) * (1 / 4) a5_2 = 3 / 8 a33_2 = 1 / 4 a_2 = 1 - Nc * a3_2 - Nc * a5_2 - binomial(Nc, 2) * a33_2 a3_3 = -(Nc ** 2 + 10 * Nc + 24) * (1 / 16) a5_3 = (1 / 16) * (3 * (Nc + 6)) a33_3 = (Nc + 6) * (1 / 8) a7_3 = -5 / 16 a35_3 = -3 / 16 a333_3 = -1 / 8 a_3 = 1 - Nc * a3_3 - Nc * a5_3 - binomial(Nc, 2) * a33_3 - Nc * a7_3 - 2 * binomial(Nc, 2) * a35_3 - binomial(Nc, 3) * a333_3 a3_4 = -(Nc ** 3 + 18 * Nc ** 2 + 104 * Nc + 192) * (1 / 96) a5_4 = (3 * Nc ** 2 + 32 * Nc + 154) * (1 / 64) a33_4 = (Nc ** 2 + 14 * Nc + 58) * (1 / 32) a7_4 = -45 / 32 a35_4 = -(3 * Nc + 29) * (1 / 32) a333_4 = -(Nc + 8) * (1 / 16) a9_4 = 35 / 128 a55_4 = 29 / 64 a335_4 = 3 / 32 a3333_4 = 1 / 16 a73_4 = 0 a_4 = 1 - Nc * a3_4 - Nc * a5_4 - Nc * a7_4 - Nc * a9_4 - (binomial(Nc, 4) * a3333_4) - ( binomial(Nc, 3) * a333_4) - (3 * binomial(Nc, 3) * a335_4) - (binomial(Nc, 2) * a33_4) - ( 2 * binomial(Nc, 2) * a35_4) - (binomial(Nc, 2) * a55_4) coeffs_1 = [ a_1, a3_1 ] coeffs_2 = [ a_2, a3_2, a5_2, a33_2 ] coeffs_3 = [ a_3, a3_3, a5_3, a33_3, a7_3, a35_3, a333_3 ] coeffs_4 = [ a_4, a3_4, a5_4, a33_4, a7_4, a35_4, a333_4, a9_4, a73_4, a55_4, a335_4, a3333_4 ] coeffs = [coeffs_1, coeffs_2, coeffs_3, coeffs_4] return coeffs[n - 1]
def Q(n): return binomial(N-1, n) * (tau**n) * (1 - tau)**(N - n - 1)
def compute(self, tau0=0.0, epsilon=1e-6, CW_min=32, CW_max=1024): """ Calculate model parameters iteratively. Keyword arguments: tau0 -- initial guess for tau (0 < tau0 < 1, default 0.0) epsilon -- desired precision (default 1e-6) CW_min -- ieee specified congestion window (default=32) CW_max -- ieee specified congestion window (default=1024) """ # Pe is defined to be 1 in the paper pe = 1 # IEEE specification m = int(math.log(CW_max/CW_min, 2)) L = self.L N = self.N # guess initial value of tau tau = tau0 # alpha is specified in paper to 0.5 alpha = 0.5 def W(j): assert(j >= 0) assert(j <= L) return 2**j*CW_min if j < m else CW_max # Equation (6) def Q(n): return binomial(N-1, n) * (tau**n) * (1 - tau)**(N - n - 1) while True: # Equation (2) - aka. p_tau(tau, ) P = 1 - (1 - tau) ** (N - 1) Pdrop = P**(L+1) if Pdrop == 1: print("warn Pdrop=1, tau={}, P={}\n".format(tau, P)) pei = (1 - tau)**(N-1) # Equation (3) pes = binomial(N-1, 1) * tau * (1 - tau)**(N-2) pec = 1 - pei - pes pss = 1/W(0) psi = 1 - pss # Equation (8) CW_avg = suml( lambda i: (1-P) * (P**i) * W(i)/(1-Pdrop), (0, L)) # Equation (7) pci = suml(lambda n: Q(n) * (1 - 1/CW_avg)**n, (2, N-1)) # Equation (9) pcs = suml( lambda n: Q(n) * n * (1/CW_avg) * (1 - 1/CW_avg)**(n-1), (2, N-1)) pcc = 1 - pci - pcs # Equation (10) pi = np.array([ [pei, pes, pec], [psi, pss, 0], [pci, pcs, pcc] ]) # A = [ Pi Ps Pc ] A = solve_steady_state(pi, epsilon) PI = A[0] # Equation (4) Pd = PI * pe # Equation (5) Pf = 1 - Pd # Equation (1) #tau_newp =(1 - P**(L+1)) / ((1 - P) * sum([1 + (1/(1-Pf)) * sum([(W(j) - k)/W(j) for k in range(1,W(j))]) * P**j for j in range(0,L+1)])) tau_new = (1 - P**(L+1)) / ((1 - P) * suml( lambda j: (1 + (1/(1-Pf)) * suml( lambda k: (W(j) - k)/W(j), (1, W(j)-1)) ) * P**j, (0, L))) # tau_i = alpha*tau_{i-1} + (1-alpha) * tau_new tau_old = tau tau = alpha * tau_old + (1 - alpha) * tau_new if abs(tau - tau_old) <= epsilon: break return tau, P, Pf
def func(n, i, t): poly = binomial(n, i) * t**(i) * (1. - t)**(n - i) return poly
def split_weights(n, r): """Auxiliary function that gets the required binomials. """ v0 = binomial(n - 1, r) v1 = binomial(n - 1, r - 1) return v0 / (v0 + v1), v1 / (v0 + v1)
def binomial_prefactor(s: int, ia: int, ib: int, xpa: float, xpb: float) -> float: return sum( binomial(ia, s - t) * binomial(ib, t) * (xpa**(ia - s + t)) * (xpb**(ib - t)) for t in range(s + 1) if (s - ia) <= t and t <= ib)
def run_simulation(corr, means, vars, T, sampsis, tprobs, nparts, nsimul, nrdmax, dfdef=1, locdef=0, scaledef=1, cov_est='hmsd', beta_Z=.2, postau=1, nest=4, cnum=0, prec=4, sups=True, mlw=110, getresults=False, tex=True, fnamepref='results_'): # Inputs # corr: 2-element tuple, specified correlation between X and Y0, and X and # tau # means: 3-element vector, specified means for X, Y0, and tau # vars: 3-element vector, specified variance for X, and variances for eps_Y0 # and eps_tau, see the note below # T: scalar, number of tuples in the simulated data # sampsis: vector, different sizes for random samples to draw # tprobs: vector, different treatment probabilities for each sample size # nparts: scalar, number of partitions on X # nsimul: scalar, number of simulations to run # nrdmax: scalar, maximum number of iterations to use for randomization # distributions # dfdef: scalar, default degrees of freedom for chi2 distribution of Y0 if # corr(X,Y0) = 0 # locdef: scalar, default location parameter for Gumbel distribution of tau # if corr(X,tau) = 0 # scaledef: scalar, default scale parameter for Gumbel distribution of tau # if corr(X,tau) = 0 # cov_est: string, specifies the covariance estimator to use for the OLS # estimation # beta_Z: scalar, used in the construction of Y0 and tau (see the note # below) # postau: integer, position of the estimate of tau (the coefficient on the # treatment dummy) in all models to be estimated # nest: integer, number of models to be estimated # cnum: integer, index of the correlation pair for the current simulation in # the vector of correlation pairs (necessary to set the random number # generator's seed to run this in parallel) # prec: integer, precision for floating point number printing in results # sups: boolean, if true, number which are too small to be printed using the # selected printing precision will be printed as zero # mlw: integer, maximum line width for printing results # getresults: boolean, if true, the function returns the results as a pandas # DataFrame (usually unnecessary, since it also prints them and # can provide tex tables, see below) # tex: boolean, if true, saves results as tex tables # fnamepref: string, prefix for file names for tex tables (only matters if # tex is true) # # Outputs # results: DataFrame, contains the results # # Note # To generate the three variables I need, I start with X as an exponentially # distributed random variable. Then, I generate the other two variables # based on that. Let Z denote any of them. I want to achieve # # Corr(X,Z) = Cov(X,Z) / sqrt(Var(X) Var(Z)) = gamma (1) # # for some gamma. I can generate # # Z = alpha + beta_Z*X + Z_eps (2) # # where Z_eps is an error term, if you will. Expanding Cov(X,Z) and # plugging in (2) yields Cov(X,Z) = beta_Z*Var(X). Also, taking the # variance of (2), I have Var(Z) = beta_Z^2*Var(X) + Var(Z_eps). Plugging # both of these into (1) gives # # beta_Z = sqrt( (Var(X) / Var(Z_eps)) * (gamma^2 / (1 - gamma^2)) ) # # and since I get to choose beta_Z, I can thereby generate random # variables with arbitrary correlation structure. I can then use alpha to # adjust the mean of the generated variable. # Set seed (since this will be run in parallel, it's actually important to # set the seed within the function, rather than outside) np.random.seed(666 + cnum) # Get scale for exponential distribution of X scale_X = np.sqrt(1 / vars[0]) # Generate X as an exponentially distributed random variable (subtract the # mean of that distribution, which is 1/scale_X, to make sure to hit the # specified mean for X) X = means[0] - (1 / scale_X) + np.random.exponential(scale_X, size=(T, 1)) # Let Y0_eps have a chi2 distribution if corr[0] != 0: # Calculate the necessary beta if there has to be a correlation beta_Y0 = (np.sqrt( (vars[1] / vars[0]) * ((corr[0]**2) / (1 - corr[0]**2)))) else: # Otherwise, set it to zero beta_Y0 = 0 # Calculate the degrees of freedom implied by this variance (this comes # from the fact that for a chi2(k) random variable, its variance is # equal to 2k) df_Y0 = .5 * vars[1] # Calculate Y0, where I need to make sure to correct for the mean of # the error term (the mean of a chi2(k) is simply k) Y0 = (means[1] - df_Y0 + beta_Y0 * X + np.random.chisquare(df_Y0, size=(T, 1))) # Let tau_eps have a Gumbel distribution if corr[1] != 0: # Calculate the necessary beta if there has to be a correlation beta_tau = (np.sqrt( (vars[2] / vars[0]) * ((corr[1]**2) / (1 - corr[1]**2)))) else: # Otherwise, it's zero beta_tau = 0 # Calculate the implied scale for the Gumbel distribution (a # Gumbel(0,b) random variable has variance b^2 (pi^2/6)) scale_tau = np.sqrt((6 / (np.pi**2)) * vars[2]) # Calculate tau, correcting for the fact that a Gumbel(0,b) random # variable has mean gb, where g is the Euler-Mascheroni constant) tau = (means[2] - np.euler_gamma * scale_tau + beta_tau * X + np.random.gumbel(0, scale_tau, size=(T, 1))) # Get the partition of X. First, X[:,0].argsort() gets the ranks in the # distribution of X. Then, nparts/T converts it into fractions of the # length of X. Taking the ceil() makes sure that the groups are between 1 # and nparts. The +1 is necessary because of Python's zero indexing, which # leads to the lowest rank being zero, and ceil(0) = 0 when it should be # equal to 1. P = np.ceil((X[:, 0].argsort() + 1) * nparts / T) # Set up a set of dummies for each but one group in the partition. Since P # is a list, each of the checks creates a list of ones and zeros which # indicate whether an element of P is equal to the current i. When # np.array() is applied to this list of lists, it stacks them as rows of a # matrix. This creates an nparts - 1 by T matrix of indicator dummies. The # transpose converts it into a more conventional format. The last group in # the partition is omitted. D = np.array([P == i + 1 for i in range(nparts - 1)], ndmin=2).transpose() # Make a vector to store the mean treatment effect estimates and mean # standard errors. This needs one row for each sample size and each # treatment probability, two columns for each estimation, two columns for # the true tau and its standard deviations, and an extra two columns for # the sample size and treatment probability. (That makes it easiert to # print the results later.) tau_hats_avg = np.zeros(shape=(len(sampsis) * len(tprobs), 4 + nest * 2)) # Go through all sample sizes for nsampsi, N in enumerate(sampsis): # Record sample size indicator in the mean estimate array tau_hats_avg[nsampsi * 2:nsampsi * 2 + 2, 0] = N # Draw random variables as the basis for a random sample of units I = np.random.normal(size=T) # Go through all groups in the partition for i in range(nparts): # Get the number of people in the group ngroup = sum(P == i + 1) # Figure out how many people to sample in this group (at least 2, # otherwise the treatment assignment by group will fail) nsamp = max(np.floor(ngroup * N / T), 2) # Get the treatment indicator for the current group. Get the # rank within group from .argsort(), add +1 to get ranks # starting at 1, divide by the number of people in the # group, and assign everyone at or below the treatment # probability to treatment. I[P == i + 1] = (I[P == i + 1].argsort() + 1) <= nsamp # The above mechanism could assign too few or too many units to # the sample. Calculate that discrepancy, as an integer. discrepancy = np.int(N - sum(I)) # Check whether the discrepancy is positive if discrepancy >= 0: # If so, iterate over all 'missing' units for i in range(discrepancy): # Make a temporary vector containing all units not in the sample temp = I[I == 0] # Pick a random integer index in that vector, and assign that # unit to the sample temp[np.random.randint(0, len(temp))] = 1 # Replace the sample assignment vector with the temporary one, # which means one more unit has now been assigned to treatment # at random. I[I == 0] = temp else: # If too many units were assigned, then the parameters for this # problem are badly set. Just print an error message. print( 'Error: Between the number of tuples, the number of groups in ', 'the partition, and the sample sizes, it is impossible to ', 'assign at least two units from each group to the sample. ', 'Please adjust the parameters. (This occured at N = ', N, '.)', sep='') # Annoyingly, the data type of I will now be float. To be used as an # index, it has to be boolean or integer. I find it easiest to convert # it to boolean by just check where it isn't zero. I = (I != 0) # Make an intercept for this sample size beta0 = np.ones(shape=(N, 1)) # Go through all treatment probabilities for nprob, p in enumerate(tprobs): # Record treatment probability in the mean estimate array tau_hats_avg[nsampsi * 2 + nprob, 1] = p # I'll need to know how many draws of treatment vectors would be # needed to get the exact randomization distribution for this # treatment probabilty and sample size. For now, just set that up # as 1. nrdexact = 1 # Set up an empty array to store the estimated tau_hat and its # standard error for each of the three models for each of the # simulations. (Each row is a given simulation, and each two # columns are for a given tau_hat and its standard error.) tau_hats = np.zeros(shape=(nsimul, nest * 2)) # Go through all simulations for the current set of parameters for s in range(nsimul): # Draw random variables as basis for treatment indicator W = np.random.normal(size=(N, 1)) # Go through all groups in the partition for i in range(nparts): # Get number of people in the group n ngroup = sum(P[I] == i + 1) # Get number of treated units k ntreat = max(np.floor(p * ngroup), 1) # Get the treatment indicator for the current group. Get the # rank within group from .argsort(), add +1 to get ranks # starting at 1. W[P[I] == i + 1, 0] = W[P[I] == i + 1, 0].argsort() + 1 <= ntreat # Check whether this is the first group and the first # simulation. If so, do the calculations required for the # number of draws in the randomization distribution. It's # convenient to do this now, since it saves some loops later # on. if s == 0 and i == 0: # If so, calculate n choose k for this group, and save # the result. (I originally did this by hand using # factorials, but using this has the nice side effect # of being evaluated as np.inf (positive infinity) in # case this runs into overflow issues, whereas my code # would result in a NaN, which I would then manually # have to change into an Inf.) nrdexact = binomial(ngroup, ntreat) elif s == 0: # If it's the first sumlation but not the first group, # get n choose k, and multiply it by the number of # possible assignments of all other groups calculated # so far nrdexact = nrdexact * binomial(ngroup, ntreat) # Generate observed outcome for the simulation regressions Yobs = Y0[I, :] + tau[I, :] * W # Generate RHS data sets for the simulation regressions # The first data set is just an intercept and a treatment dummy Z1 = np.concatenate((beta0, W), axis=1) # The second data set contains the covariate X Z2 = np.concatenate((beta0, W, X[I, :]), axis=1) # The third data set also includes the partition dummies Z3 = np.concatenate((beta0, W, D[I, :]), axis=1) # The fourth data set also includes an interaction between the # treatment dummy and the partition dummies Z4 = np.concatenate( (beta0, W, D[I, :], (W @ np.ones(shape=(1, nparts - 1))) * D[I, :]), axis=1) # Estimate the first two regression models and store the # estimates in the tau_hats array, in row s for i, Z in enumerate([Z1, Z2, Z3]): # Estimate the model beta_hat, S_hat = ols(Yobs, Z, cov_est=cov_est) # Store the estimates. The row index is easy. For the column # index, it's important to remember Python's zero indexing, # and how it assigns elements to indices. This maps counter # i to index [j,k] as # # 0 -> [0,2], 1 -> [2,4], ... # # and for any given index [j,k], Python will try to assign # contents to the elements j,j+1,...,k-1, but not to k # itself. Therefore, this gets me the right indices for a # two element assignment. tau_hats[s, 2 * i:2 * i + 2] = (beta_hat[postau, 0], np.sqrt(S_hat[postau, postau])) # For the saturated model, I need to get the average treatment # effect. First, estimate the model. beta_hat, S_hat = ols(Yobs, Z4, cov_est=cov_est) # Set up a vector of linear constraints on tau L = np.zeros(shape=(beta_hat.shape)) # Replace the element corresponding to the base effect as one, # since every group in the partition has this as part of their # estimated effect L[postau, 0] = 1 # Go through all groups in the partition for which there are # dummies in D for i in range(nparts - 1): # Get the number of treated units ntreat = sum(W[:, 0]) # Get the number of treated units in this group ntreatgroup = sum((P[I] == i + 1) * (W[:, 0] == 1)) # Replace the corresponding element of L with the # probability of being in this group, conditional on being # a treated unit. The position of that element is equal to # the length of beta_hat minus the number of groups in the # partition minus one plus the number of the group under # consideration. That is # # beta_hat.shape[0]-(nparts-1)+i # = beta_hat.shape[0]-nparts+i+1 # # remembering that due to Python's zero indexing, the number # of the group is i+1, not i. L[beta_hat.shape[0] - nparts + i + 1, 0] = ntreatgroup / ntreat # Calculate the average treatment effect for the saturated # model tau_hat_avg_satu = L.transpose() @ beta_hat # Calculate the estimated variance S_hat_satu = L.transpose() @ S_hat @ L # Store the estimate and its standard error tau_hats[s, 2 * (nest - 1):] = (tau_hat_avg_satu, np.sqrt(S_hat_satu)) # Store the average estimates and standard errors for all three # models, for the current sample size and treatment probability tau_hats_avg[nsampsi * 2 + nprob, 4:] = np.mean(tau_hats, axis=0) # Set up an array to store the randomization distribution of tau_hat # (or the maximum number of simulation draws used to approximate it, # if getting the exact distribution is not feasible.) tau_true = np.zeros(shape=(np.int(np.minimum(nrdexact, nrdmax)), 1)) # Check whether the number of iterations required to get the exact # randomization distribution exceeds the maximum allowable number # of iterations if nrdexact <= nrdmax: # If so, set up an empty list A = [] # Go through all groups in the partition for i in range(nparts): # Get number of people in the group n ngroup = sum(P[I] == i + 1) # Get number of treated units k ntreat = np.int(max(np.floor(p * sum(P[I] == i + 1)), 1)) # Get all assignment vectors for this group, and add them # to the list A.append(combinations(range(ngroup), ntreat)) # Get the Cartesian product of the assignment vectors for all # groups. Note that the asterisk matters, because that unpacks # A, which is a list of lists, before getting the product. # (Otherwise, this will just return the same three lists, since # A itself has size one: It is a single list of lists. So # without unpacking it first, product() gets the Cartesian # product of A with itself, which is just A.) A = product(*A) # Go through all possible assignment vectors for s, a in enumerate(list(A)): # Set up treatment assignment as a vector of zeros W = np.zeros(shape=(N, 1)) # Go through all groups in the partition for i in range(nparts): # Get the assignment vector for that group temp = W[P[I] == i + 1] # Replace is as one as appropriate temp[a[i], 0] = 1 # Replace the assignment vector W[P[I] == i + 1] = temp # Generate observed outcome for this assignment Yobs = Y0[I, :] + tau[I, :] * W # Put together the RHS variables Z1 = np.concatenate((beta0, W), axis=1) # Run the regression beta_hat_simp = ols(Yobs, Z1, get_cov=False) # Store the result tau_true[s, 0] = beta_hat_simp[postau, 0] else: # If getting the exact randomization distribution is too # computationally intensive, go through the maximum number of # allowable iterations for s in range(nrdmax): # Here, the treatment assignment is just as for the # simulations above # Draw random variables as basis for treatment indicator W = np.random.normal(size=(N, 1)) # Go through all groups in the partition for i in range(nparts): # Get number of people in the group n ngroup = sum(P[I] == i + 1) # Get number of treated units k ntreat = max(np.floor(p * ngroup), 1) # Get the treatment indicator for the current group. # Get the rank within group from .argsort(), add +1 to # get ranks starting at 1. W[P[I] == i + 1, 0] = W[P[I] == i + 1, 0].argsort() + 1 <= ntreat # Generate observed outcome for this assignment Yobs = Y0[I, :] + tau[I, :] * W # Put together the RHS variables Z1 = np.concatenate((beta0, W), axis=1) # Run the regression beta_hat_simp = ols(Yobs, Z1, get_cov=False) # Store the result tau_true[s, 0] = beta_hat_simp[postau, 0] # Store the expected value of tau tau_hats_avg[nsampsi * 2 + nprob, 2] = np.mean(tau_true, axis=0) # Store the standard deviation of tau tau_hats_avg[nsampsi * 2 + nprob, 3] = np.std(tau_true, axis=0) # Set display options (has to be done within each function if this runs in # parallel) pd.set_option('display.max_columns', tau_hats_avg.shape[1]) pd.set_option('display.width', mlw) pd.set_option('display.precision', prec) # Make a header line for the results, starting with the basic parameters firstline = ['N', 'p', 'tau', 'SD'] # Use Python's amazing list comprehension to make a list that goes, # [tau_hat 1, SE 1, tau_hat 2, SE 2, ...] firstline.extend(x for i in range(nest) for x in ['tau_hat ' + str(i + 1), 'SE ' + str(i + 1)]) # Put the results in a pandas DataFrame results = pd.DataFrame(data=tau_hats_avg, columns=firstline) # Make sure sample sizes are stored as integers results['N'] = results['N'].astype(int) # Get the variances for Y0 and tau to display them d_var_Y0 = (beta_Y0**2) * vars[0] + vars[1] d_var_tau = (beta_tau**2) * vars[0] + vars[2] # Print the results print('Correlations: corr(X,Y0) = ', corr[0], ', corr(X,tau) = ', corr[1], '\n', 'Variances: V[Y0] = ', np.around(d_var_Y0, prec), ', V[tau] = ', np.around(d_var_tau, prec), '\n', results, '\n', sep='') # Check whether to export to latex if tex: # Save the results as a tex table results.to_latex(fnamepref + str(cnum) + '.tex', index=False) # If desired, return results DataFrame if getresults: return results
def matrix(self, L, N, c_op_mats = None): assert(N <= 2*prod(L)) # we cannot have more particles than states num_ops = len(self.seq) assert(num_ops % 2 == 0) # we must have an even number of operators # determine dimension of hilbert space hilbert_dim = int(binomial(2*prod(L), N)) matrix_shape = (hilbert_dim, hilbert_dim) # if we have an empty sequence, return the zero matrix if num_ops == 0: return sparse.csr_matrix(matrix_shape, dtype = int) # to strictly enforce conservation of particle number, we make sure that # we have the same number of creation operators as annihilation operators assert( len([ op for op in self.seq if op.creation ]) == len([ op for op in self.seq if not op.creation ]) ) # sort all operators in a standard order self.sort() # identify creation / destruction operators and their indices created_states = [ op.index(L) for op in self.seq[:num_ops//2] ] destroyed_states = [ op.index(L) for op in self.seq[num_ops//2:][::-1] ] # if we address any states twice, return the zero matrix if len(set(created_states)) + len(set(destroyed_states)) != num_ops: return sparse.csr_matrix(matrix_shape, dtype = int) # if we provided matrix representations of the fermionic operators, use them! if c_op_mats != None: if len(c_op_mats) < (2*prod(L))*(num_ops//2): error_msg = "we need {} operators, but have only {}!" sys.exit(error_msg.format((2*prod(L))*(num_ops//2),len(c_op_mats))) op_list = ( [ c_op_mats[(2*prod(L))*ii + created_states[ii]].T for ii in range(num_ops//2) ] + [ c_op_mats[(2*prod(L))*ii + destroyed_states[ii]] for ii in range(num_ops//2) ][::-1] ) matrix = functools.reduce(sparse.csr_matrix.dot, op_list) return self.prefactor * matrix # we do not have a matrix representation of fermionic operators, so we have # to "manually" loop over all elements of the fock basis to construct a matrix diagonal_term = created_states == destroyed_states matrix = sparse.dok_matrix(matrix_shape, dtype = int) for index_in, states_in in fock_state_basis(L, N): # if this combination of single particle states is not addressed # by the destruction operators, continue to next combination if any([ state not in states_in for state in destroyed_states ]): continue # if this term is diagonal in the fock basis and we address this state, # set the diagonal matrix element to 1 if diagonal_term: matrix[index_in, index_in] = 1 continue # determine which will states remain occupied after destruction remaining_states_in = [ state for state in states_in if state not in destroyed_states ] # count the number of minus signs we get from applying destruction operators signs_in = sum([ sum([ 1 for state in states_in if state > destroyed_state ]) for destroyed_state in destroyed_states ]) # otherwise, we need to look at all off-diagonal matrix elements for index_out, states_out in fock_state_basis(L, N): if any([ state not in states_out for state in created_states ]): continue remaining_states_out = [ state for state in states_out if state not in created_states ] # if the remaining input/output states are different # this matrix element is zero if remaining_states_in != remaining_states_out: continue signs_out = sum([ sum([ 1 for state in states_out if state > created_state ]) for created_state in created_states ]) # set this matrix element to 1 or -1 appropriately matrix[index_out, index_in] = (-1)**(signs_in + signs_out) return self.prefactor * matrix.tocsr()
def fock_state_basis(L, N): hilbert_dim = int(binomial(2*prod(L),N)) return zip(range(hilbert_dim), itertools.combinations(range(2*prod(L)),N))
def find_maximal_ck(state_number: int, k: int) -> int: ck = 0 while int(binomial(ck, k)) <= state_number: ck += 1 return ck - 1