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
Example #2
0
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]
Example #3
0
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
Example #5
0
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...")
Example #8
0
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
Example #9
0
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
Example #11
0
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)
Example #12
0
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
Example #13
0
    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
Example #14
0
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
Example #15
0
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}
Example #16
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
Example #17
0
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]
Example #18
0
 def Q(n):
     return binomial(N-1, n) * (tau**n) * (1 - tau)**(N - n - 1)
Example #19
0
    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
Example #21
0
 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)
Example #23
0
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))
Example #26
0
def find_maximal_ck(state_number: int, k: int) -> int:
    ck = 0
    while int(binomial(ck, k)) <= state_number:
        ck += 1
    return ck - 1