Instruction:
Can you generate a brief explanation for the following Python 3 code
def bm_calc(self,ref_code_bits, rec_code_bits, metric_type, quant_level):
        distance = 0
        if metric_type == 'soft': # squared distance metric
            bits = binary(int(ref_code_bits),self.rate.denominator)
            for k in range(len(bits)):
                ref_bit = (2**quant_level-1)*int(bits[k],2)
                distance += (int(rec_code_bits[k]) - ref_bit)**2
        elif metric_type == 'hard': # hard decisions
            bits = binary(int(ref_code_bits),self.rate.denominator)
            for k in range(len(rec_code_bits)):
                distance += abs(rec_code_bits[k] - int(bits[k]))
        elif metric_type == 'unquant': # unquantized
            bits = binary(int(ref_code_bits),self.rate.denominator)
            for k in range(len(bits)):
                distance += (float(rec_code_bits[k])-float(bits[k]))**2
        else:
            print('Invalid metric type specified')
            raise ValueError('Invalid metric type specified. Use soft, hard, or unquant')
        return distance

Response: Calculates the distance between two records in the branch and a given metric type and quant level.


Instruction:
Can you write a function in Python 3 where it
outputs state = conv_encoder(input,state) We get the 1/2 or 1/3 rate from self.rate Polys G1 and G2 are entered as binary strings, e.g, G1 = '111' and G2 = '101' for K = 3 G1 = '1011011' and G2 = '1111001' for K = 7 G3 is also included for rate 1/3 Input state as a binary string of length K-1, e.g., '00' or '0000000' e.g., state = '00' for K = 3 e.g., state = '000000' for K = 7 Mark Wickert and Andrew Smit 2018

Response:
def conv_encoder(self,input,state):
        """
        output, state = conv_encoder(input,state)
        We get the 1/2 or 1/3 rate from self.rate
        Polys G1 and G2 are entered as binary strings, e.g,
        G1 = '111' and G2 = '101' for K = 3
        G1 = '1011011' and G2 = '1111001' for K = 7
        G3 is also included for rate 1/3
        Input state as a binary string of length K-1, e.g., '00' or '0000000'
        e.g., state = '00' for K = 3
        e.g., state = '000000' for K = 7
        Mark Wickert and Andrew Smit 2018
        """

        output = []

        if(self.rate == Fraction(1,2)):
            for n in range(len(input)):
                u1 = int(input[n])
                u2 = int(input[n])
                for m in range(1,self.constraint_length):
                    if int(self.G_polys[0][m]) == 1: # XOR if we have a connection
                        u1 = u1 ^ int(state[m-1])
                    if int(self.G_polys[1][m]) == 1: # XOR if we have a connection
                        u2 = u2 ^ int(state[m-1])
                # G1 placed first, G2 placed second
                output = np.hstack((output, [u1, u2]))
                state = bin(int(input[n]))[-1] + state[:-1]
        elif(self.rate == Fraction(1,3)):
            for n in range(len(input)):
                if(int(self.G_polys[0][0]) == 1):
                    u1 = int(input[n])
                else:
                    u1 = 0
                if(int(self.G_polys[1][0]) == 1):
                    u2 = int(input[n])
                else:
                    u2 = 0
                if(int(self.G_polys[2][0]) == 1):
                    u3 = int(input[n])
                else:
                    u3 = 0
                for m in range(1,self.constraint_length):
                    if int(self.G_polys[0][m]) == 1: # XOR if we have a connection
                        u1 = u1 ^ int(state[m-1])
                    if int(self.G_polys[1][m]) == 1: # XOR if we have a connection
                        u2 = u2 ^ int(state[m-1])
                    if int(self.G_polys[2][m]) == 1: # XOR if we have a connection
                        u3 = u3 ^ int(state[m-1])
                # G1 placed first, G2 placed second, G3 placed third
                output = np.hstack((output, [u1, u2, u3]))

                state = bin(int(input[n]))[-1] + state[:-1]

        return output, state


Instruction:
Write a Python 3 script to
apply puncture to the serial bits produced by convolutionally encoding.

Response:
def puncture(self,code_bits,puncture_pattern = ('110','101')):
        """
        Apply puncturing to the serial bits produced by convolutionally
        encoding.

        :param code_bits:
        :param puncture_pattern:
        :return:

        Examples
        --------
        This example uses the following puncture matrix:

        .. math::

           \\begin{align*}
               \\mathbf{A} = \\begin{bmatrix}
                1 & 1 & 0 \\\\
                1 & 0 & 1
                \\end{bmatrix}
           \\end{align*}

        The upper row operates on the outputs for the :math:`G_{1}` polynomial and the lower row operates on the outputs of
        the  :math:`G_{2}`  polynomial.

        >>> import numpy as np
        >>> from sk_dsp_comm.fec_conv import fec_conv
        >>> cc = fec_conv(('101','111'))
        >>> x = np.array([0, 0, 1, 1, 1, 0, 0, 0, 0, 0])
        >>> state = '00'
        >>> y, state = cc.conv_encoder(x, state)
        >>> cc.puncture(y, ('110','101'))
        array([ 0.,  0.,  0.,  1.,  1.,  0.,  0.,  0.,  1.,  1.,  0.,  0.])
        """
        # Check to see that the length of code_bits is consistent with a rate
        # 1/2 code.
        L_pp = len(puncture_pattern[0])
        N_codewords = int(np.floor(len(code_bits)/float(2)))
        if 2*N_codewords != len(code_bits):
            warnings.warn('Number of code bits must be even!')
            warnings.warn('Truncating bits to be compatible.')
            code_bits = code_bits[:2*N_codewords]
        # Extract the G1 and G2 encoded bits from the serial stream.
        # Assume the stream is of the form [G1 G2 G1 G2 ...   ]
        x_G1 = code_bits.reshape(N_codewords,2).take([0],
                                 axis=1).reshape(1,N_codewords).flatten()
        x_G2 = code_bits.reshape(N_codewords,2).take([1],
                                 axis=1).reshape(1,N_codewords).flatten()
        # Check to see that the length of x_G1 and x_G2 is consistent with the
        # length of the puncture pattern
        N_punct_periods = int(np.floor(N_codewords/float(L_pp)))
        if L_pp*N_punct_periods != N_codewords:
            warnings.warn('Code bit length is not a multiple pp = %d!' % L_pp)
            warnings.warn('Truncating bits to be compatible.')
            x_G1 = x_G1[:L_pp*N_punct_periods]
            x_G2 = x_G2[:L_pp*N_punct_periods]
        #Puncture x_G1 and x_G1
        g1_pp1 = [k for k,g1 in enumerate(puncture_pattern[0]) if g1 == '1']
        g2_pp1 = [k for k,g2 in enumerate(puncture_pattern[1]) if g2 == '1']
        N_pp = len(g1_pp1)
        y_G1 = x_G1.reshape(N_punct_periods,L_pp).take(g1_pp1,
                            axis=1).reshape(N_pp*N_punct_periods,1)
        y_G2 = x_G2.reshape(N_punct_periods,L_pp).take(g2_pp1,
                            axis=1).reshape(N_pp*N_punct_periods,1)
        # Interleave y_G1 and y_G2 for modulation via a serial bit stream
        y = np.hstack((y_G1,y_G2)).reshape(1,2*N_pp*N_punct_periods).flatten()
        return y


Instruction:
Create a Python 3 function to
return the values of the given soft bits in the channel that can be used to decode the next set of soft bits.

Response:
def depuncture(self,soft_bits,puncture_pattern = ('110','101'),
                   erase_value = 3.5):
        """
        Apply de-puncturing to the soft bits coming from the channel. Erasure bits
        are inserted to return the soft bit values back to a form that can be
        Viterbi decoded.

        :param soft_bits:
        :param puncture_pattern:
        :param erase_value:
        :return:

        Examples
        --------
        This example uses the following puncture matrix:

        .. math::

           \\begin{align*}
               \\mathbf{A} = \\begin{bmatrix}
                1 & 1 & 0 \\\\
                1 & 0 & 1
                \\end{bmatrix}
           \\end{align*}

        The upper row operates on the outputs for the :math:`G_{1}` polynomial and the lower row operates on the outputs of
        the  :math:`G_{2}`  polynomial.

        >>> import numpy as np
        >>> from sk_dsp_comm.fec_conv import fec_conv
        >>> cc = fec_conv(('101','111'))
        >>> x = np.array([0, 0, 1, 1, 1, 0, 0, 0, 0, 0])
        >>> state = '00'
        >>> y, state = cc.conv_encoder(x, state)
        >>> yp = cc.puncture(y, ('110','101'))
        >>> cc.depuncture(yp, ('110', '101'), 1)
        array([ 0., 0., 0., 1., 1., 1., 1., 0., 0., 1., 1., 0., 1., 1., 0., 1., 1., 0.]
        """
        # Check to see that the length of soft_bits is consistent with a rate
        # 1/2 code.
        L_pp = len(puncture_pattern[0])
        L_pp1 = len([g1 for g1 in puncture_pattern[0] if g1 == '1'])
        L_pp0 = len([g1 for g1 in puncture_pattern[0] if g1 == '0'])
        #L_pp0 = len([g1 for g1 in pp1 if g1 == '0'])
        N_softwords = int(np.floor(len(soft_bits)/float(2)))
        if 2*N_softwords != len(soft_bits):
            warnings.warn('Number of soft bits must be even!')
            warnings.warn('Truncating bits to be compatible.')
            soft_bits = soft_bits[:2*N_softwords]
        # Extract the G1p and G2p encoded bits from the serial stream.
        # Assume the stream is of the form [G1p G2p G1p G2p ...   ],
        # which for QPSK may be of the form [Ip Qp Ip Qp Ip Qp ...    ]
        x_G1 = soft_bits.reshape(N_softwords,2).take([0],
                                 axis=1).reshape(1,N_softwords).flatten()
        x_G2 = soft_bits.reshape(N_softwords,2).take([1],
                                 axis=1).reshape(1,N_softwords).flatten()
        # Check to see that the length of x_G1 and x_G2 is consistent with the
        # puncture length period of the soft bits
        N_punct_periods = int(np.floor(N_softwords/float(L_pp1)))
        if L_pp1*N_punct_periods != N_softwords:
            warnings.warn('Number of soft bits per puncture period is %d' % L_pp1)
            warnings.warn('The number of soft bits is not a multiple')
            warnings.warn('Truncating soft bits to be compatible.')
            x_G1 = x_G1[:L_pp1*N_punct_periods]
            x_G2 = x_G2[:L_pp1*N_punct_periods]
        x_G1 = x_G1.reshape(N_punct_periods,L_pp1)
        x_G2 = x_G2.reshape(N_punct_periods,L_pp1)
        #Depuncture x_G1 and x_G1
        g1_pp1 = [k for k,g1 in enumerate(puncture_pattern[0]) if g1 == '1']
        g1_pp0 = [k for k,g1 in enumerate(puncture_pattern[0]) if g1 == '0']
        g2_pp1 = [k for k,g2 in enumerate(puncture_pattern[1]) if g2 == '1']
        g2_pp0 = [k for k,g2 in enumerate(puncture_pattern[1]) if g2 == '0']
        x_E = erase_value*np.ones((N_punct_periods,L_pp0))
        y_G1 = np.hstack((x_G1,x_E))
        y_G2 = np.hstack((x_G2,x_E))
        [g1_pp1.append(val) for idx,val in enumerate(g1_pp0)]
        g1_comp = list(zip(g1_pp1,list(range(L_pp))))
        g1_comp.sort()
        G1_col_permute = [g1_comp[idx][1] for idx in range(L_pp)]
        [g2_pp1.append(val) for idx,val in enumerate(g2_pp0)]
        g2_comp = list(zip(g2_pp1,list(range(L_pp))))
        g2_comp.sort()
        G2_col_permute = [g2_comp[idx][1] for idx in range(L_pp)]
        #permute columns to place erasure bits in the correct position
        y = np.hstack((y_G1[:,G1_col_permute].reshape(L_pp*N_punct_periods,1),
                       y_G2[:,G2_col_permute].reshape(L_pp*N_punct_periods,
                       1))).reshape(1,2*L_pp*N_punct_periods).flatten()
        return y


Instruction:
Can you implement a function in Python 3 that
returns a trellis diagram of the possible state transitions.

Response:
def trellis_plot(self,fsize=(6,4)):
        """
        Plots a trellis diagram of the possible state transitions.

        Parameters
        ----------
        fsize : Plot size for matplotlib.

        Examples
        --------
        >>> import matplotlib.pyplot as plt
        >>> from sk_dsp_comm.fec_conv import fec_conv
        >>> cc = fec_conv()
        >>> cc.trellis_plot()
        >>> plt.show()
        """

        branches_from = self.branches
        plt.figure(figsize=fsize)

        plt.plot(0,0,'.')
        plt.axis([-0.01, 1.01, -(self.Nstates-1)-0.05, 0.05])
        for m in range(self.Nstates):
            if branches_from.input1[m] == 0:
                plt.plot([0, 1],[-branches_from.states1[m], -m],'b')
                plt.plot([0, 1],[-branches_from.states1[m], -m],'r.')
            if branches_from.input2[m] == 0:
                plt.plot([0, 1],[-branches_from.states2[m], -m],'b')
                plt.plot([0, 1],[-branches_from.states2[m], -m],'r.')
            if branches_from.input1[m] == 1:
                plt.plot([0, 1],[-branches_from.states1[m], -m],'g')
                plt.plot([0, 1],[-branches_from.states1[m], -m],'r.')
            if branches_from.input2[m] == 1:
                plt.plot([0, 1],[-branches_from.states2[m], -m],'g')
                plt.plot([0, 1],[-branches_from.states2[m], -m],'r.')
        #plt.grid()
        plt.xlabel('One Symbol Transition')
        plt.ylabel('-State Index')
        msg = 'Rate %s, K = %d Trellis' %(self.rate, int(np.ceil(np.log2(self.Nstates)+1)))
        plt.title(msg)


Instruction:
Explain what the following Python 3 code does
def traceback_plot(self,fsize=(6,4)):
        traceback_states = self.paths.traceback_states
        plt.figure(figsize=fsize)
        plt.axis([-self.decision_depth+1, 0,
                  -(self.Nstates-1)-0.5, 0.5])
        M,N = traceback_states.shape
        traceback_states = -traceback_states[:,::-1]

        plt.plot(range(-(N-1),0+1),traceback_states.T)
        plt.xlabel('Traceback Symbol Periods')
        plt.ylabel('State Index $0$ to -$2^{(K-1)}$')
        plt.title('Survivor Paths Traced Back From All %d States' % self.Nstates)
        plt.grid()

Response: Plot the traceback of the possible last 4 states.


Instruction:
Make a summary of the following Python 3 code
def up(self,x):
        y = self.M*ssd.upsample(x,self.M)
        y = signal.lfilter(self.b,self.a,y)
        return y

Response: Upsample and filter the signal


Instruction:
Can you tell what is the following Python 3 function doing
def dn(self,x):
        y = signal.lfilter(self.b,self.a,x)
        y = ssd.downsample(y,self.M)
        return y

Response: Downsample and filter the signal


Instruction:
Can you tell what is the following Python 3 function doing
def filter(self,x):
        y = signal.lfilter(self.b,[1],x)
        return y

Response: Filter the signal by the given value


Instruction:
Create a Python 3 function to
plot the poles and zeros of the FIR filter in the z - plane

Response:
def zplane(self,auto_scale=True,size=2,detect_mult=True,tol=0.001):
        """
        Plot the poles and zeros of the FIR filter in the z-plane
        """
        ssd.zplane(self.b,[1],auto_scale,size,tol)


Instruction:
Make a summary of the following Python 3 code
def filter(self,x):
        y = signal.sosfilt(self.sos,x)
        return y

Response: Filter the signal using second - order sections


Instruction:
Given the following Python 3 function, write the documentation
def dn(self,x,M_change = 12):
        y = signal.sosfilt(self.sos,x)
        y = ssd.downsample(y,M_change)
        return y

Response: Downsample and filter the signal


Instruction:
How would you code a function in Python 3 to
plot the frequency response of the current species

Response:
def freq_resp(self, mode= 'dB', fs = 8000, ylim = [-100,2]):
        """
        Frequency response plot
        """
        iir_d.freqz_resp_cas_list([self.sos],mode,fs=fs)
        pylab.grid()
        pylab.ylim(ylim)


Instruction:
Can you create a Python 3 function that
plots the poles and zeros of the FIR filter in the z - plane

Response:
def zplane(self,auto_scale=True,size=2,detect_mult=True,tol=0.001):
        """
        Plot the poles and zeros of the FIR filter in the z-plane
        """
        iir_d.sos_zplane(self.sos,auto_scale,size,tol)


Instruction:
Given the following Python 3 function, write the documentation
def ser2ber(q,n,d,t,ps):
    lnps = len(ps) # len of error vector
    ber = np.zeros(lnps) # inialize output vector
    for k in range(0,lnps): # iterate error vector
        ser = ps[k] # channel symbol error rate
        sum1 = 0 # initialize sums
        sum2 = 0
        for i in range(t+1,d+1):
            term = special.comb(n,i)*(ser**i)*((1-ser))**(n-i)
            sum1 = sum1 + term
        for i in range(d+1,n+1):
            term = (i)*special.comb(n,i)*(ser**i)*((1-ser)**(n-i))
            sum2 = sum2+term
        ber[k] = (q/(2*(q-1)))*((d/n)*sum1+(1/n)*sum2)

    return ber

Response: This function converts a symbol error rate to bit error rate.


Instruction:
Can you implement a function in Python 3 that
finds the bit error probability bounds according to Ziemer and Tranter page 656. parameters: ----------- j: number of parity bits used in single error correction block code SNRdB: Eb/N0 values in dB coded: Select single error correction code (True) or uncoded (False) M: modulation order returns: -------- Pb: bit error probability bound

Response:
def block_single_error_Pb_bound(j,SNRdB,coded=True,M=2):
    """
    Finds the bit error probability bounds according to Ziemer and Tranter
    page 656.

    parameters:
    -----------
    j: number of parity bits used in single error correction block code
    SNRdB: Eb/N0 values in dB
    coded: Select single error correction code (True) or uncoded (False)
    M: modulation order

    returns:
    --------
    Pb: bit error probability bound

    """
    Pb = np.zeros_like(SNRdB)
    Ps = np.zeros_like(SNRdB)
    SNR = 10.**(SNRdB/10.)
    n = 2**j-1
    k = n-j

    for i,SNRn in enumerate(SNR):
        if coded: # compute Hamming code Ps
            if M == 2:
                Ps[i] = Q_fctn(np.sqrt(k*2.*SNRn/n))
            else:
                Ps[i] = 4./np.log2(M)*(1 - 1/np.sqrt(M))*\
                        np.gaussQ(np.sqrt(3*np.log2(M)/(M-1)*SNRn))/k
        else: # Compute Uncoded Pb
            if M == 2:
                Pb[i] = Q_fctn(np.sqrt(2.*SNRn))
            else:
                Pb[i] = 4./np.log2(M)*(1 - 1/np.sqrt(M))*\
                        np.gaussQ(np.sqrt(3*np.log2(M)/(M-1)*SNRn))

    # Convert symbol error probability to bit error probability
    if coded:
        Pb = ser2ber(M,n,3,1,Ps)
    return Pb


Instruction:
Given the following Python 3 function, write the documentation
def hamm_gen(self,j):
        if(j < 3):
            raise ValueError('j must be > 2')

        # calculate codeword length
        n = 2**j-1

        # calculate source bit length
        k = n-j

        # Allocate memory for Matrices
        G = np.zeros((k,n),dtype=int)
        H = np.zeros((j,n),dtype=int)
        P = np.zeros((j,k),dtype=int)
        R = np.zeros((k,n),dtype=int)

        # Encode parity-check matrix columns with binary 1-n
        for i in range(1,n+1):
            b = list(binary(i,j))
            for m in range(0,len(b)):
                b[m] = int(b[m])
            H[:,i-1] = np.array(b)

        # Reformat H to be systematic
        H1 = np.zeros((1,j),dtype=int)
        H2 = np.zeros((1,j),dtype=int)
        for i in range(0,j):
            idx1 = 2**i-1
            idx2 = n-i-1
            H1[0,:] = H[:,idx1]
            H2[0,:] = H[:,idx2]
            H[:,idx1] = H2
            H[:,idx2] = H1

        # Get parity matrix from H
        P = H[:,:k]

        # Use P to calcuate generator matrix P
        G[:,:k] = np.diag(np.ones(k))
        G[:,k:] = P.T

        # Get k x k identity matrix
        R[:,:k] = np.diag(np.ones(k))

        return G, H, R, n, k

Response: Generate parity check matrix G H and generator matrix H and R.


Instruction:
Write a Python 3 function that can
encode input bit array x using hamming block code. parameters ---------- x: array of source bits to be encoded by block encoder. returns ------- codewords: array of code words generated by generator matrix G and input x. Andrew Smit November 2018

Response:
def hamm_encoder(self,x):
        """
        Encodes input bit array x using hamming block code.

        parameters
        ----------
        x: array of source bits to be encoded by block encoder.

        returns
        -------
        codewords: array of code words generated by generator
        matrix G and input x.

        Andrew Smit November 2018
        """
        if(np.dtype(x[0]) != int):
            raise ValueError('Error: Invalid data type. Input must be a vector of ints')

        if(len(x) % self.k or len(x) < self.k):
            raise ValueError('Error: Invalid input vector length. Length must be a multiple of %d' %self.k)

        N_symbols = int(len(x)/self.k)
        codewords = np.zeros(N_symbols*self.n)
        x = np.reshape(x,(1,len(x)))

        for i in range(0,N_symbols):
            codewords[i*self.n:(i+1)*self.n] = np.matmul(x[:,i*self.k:(i+1)*self.k],self.G)%2
        return codewords


Instruction:
Can you write a function in Python 3 where it
decodes hamming encoded codewords. Make sure code words are of the appropriate length for the object. parameters --------- codewords: bit array of codewords returns ------- decoded_bits: bit array of decoded source bits Andrew Smit November 2018

Response:
def hamm_decoder(self,codewords):
        """
        Decode hamming encoded codewords. Make sure code words are of
        the appropriate length for the object.

        parameters
        ---------
        codewords: bit array of codewords

        returns
        -------
        decoded_bits: bit array of decoded source bits

        Andrew Smit November 2018
        """
        if(np.dtype(codewords[0]) != int):
            raise ValueError('Error: Invalid data type. Input must be a vector of ints')

        if(len(codewords) % self.n or len(codewords) < self.n):
            raise ValueError('Error: Invalid input vector length. Length must be a multiple of %d' %self.n)

        # Calculate the number of symbols (codewords) in the input array
        N_symbols = int(len(codewords)/self.n)

        # Allocate memory for decoded sourcebits
        decoded_bits = np.zeros(N_symbols*self.k)

        # Loop through codewords to decode one block at a time
        codewords = np.reshape(codewords,(1,len(codewords)))
        for i in range(0,N_symbols):

            # find the syndrome of each codeword
            S = np.matmul(self.H,codewords[:,i*self.n:(i+1)*self.n].T) % 2

            # convert binary syndrome to an integer
            bits = ''
            for m in range(0,len(S)):
                bit = str(int(S[m,:]))
                bits = bits + bit
            error_pos = int(bits,2)
            h_pos = self.H[:,error_pos-1]

            # Use the syndrome to find the position of an error within the block
            bits = ''
            for m in range(0,len(S)):
                bit = str(int(h_pos[m]))
                bits = bits + bit
            decoded_pos = int(bits,2)-1

            # correct error if present
            if(error_pos):
                codewords[:,i*self.n+decoded_pos] = (codewords[:,i*self.n+decoded_pos] + 1) % 2

            # Decode the corrected codeword
            decoded_bits[i*self.k:(i+1)*self.k] = np.matmul(self.R,codewords[:,i*self.n:(i+1)*self.n].T).T % 2
        return decoded_bits.astype(int)


Instruction:
Can you create a Python 3 function that
encodes input bit array x using cyclic block code. parameters ---------- x: vector of source bits to be encoded by block encoder. Numpy array of integers expected. returns ------- codewords: vector of code words generated from input vector Andrew Smit November 2018

Response:
def cyclic_encoder(self,x,G='1011'):
        """
        Encodes input bit array x using cyclic block code.

        parameters
        ----------
        x: vector of source bits to be encoded by block encoder. Numpy array
           of integers expected.

        returns
        -------
        codewords: vector of code words generated from input vector

        Andrew Smit November 2018
        """

        # Check block length
        if(len(x) % self.k or len(x) < self.k):
            raise ValueError('Error: Incomplete block in input array. Make sure input array length is a multiple of %d' %self.k)

        # Check data type of input vector
        if(np.dtype(x[0]) != int):
            raise ValueError('Error: Input array should be int data type')

        # Calculate number of blocks
        Num_blocks = int(len(x) / self.k)

        codewords = np.zeros((Num_blocks,self.n),dtype=int)
        x = np.reshape(x,(Num_blocks,self.k))

        #print(x)

        for p in range(Num_blocks):
            S = np.zeros(len(self.G))
            codeword = np.zeros(self.n)
            current_block = x[p,:]
            #print(current_block)
            for i in range(0,self.n):
                if(i < self.k):
                    S[0] = current_block[i]
                    S0temp = 0
                    for m in range(0,len(self.G)):
                        if(self.G[m] == '1'):
                            S0temp = S0temp + S[m]
                            #print(j,S0temp,S[j])
                    S0temp = S0temp % 2
                    S = np.roll(S,1)
                    codeword[i] = current_block[i]
                    S[1] = S0temp
                else:
                    out = 0
                    for m in range(1,len(self.G)):
                        if(self.G[m] == '1'):
                            out = out + S[m]
                    codeword[i] = out % 2
                    S = np.roll(S,1)
                    S[1] = 0
            codewords[p,:] = codeword
            #print(codeword)

        codewords = np.reshape(codewords,np.size(codewords))

        return codewords.astype(int)


Instruction:
Write a Python 3 function for
decoding a vector of cyclic coded codewords. parameters ---------- codewords: vector of codewords to be decoded. Numpy array of integers expected. returns ------- decoded_blocks: vector of decoded bits Andrew Smit November 2018

Response:
def cyclic_decoder(self,codewords):
        """
        Decodes a vector of cyclic coded codewords.

        parameters
        ----------
        codewords: vector of codewords to be decoded. Numpy array of integers expected.

        returns
        -------
        decoded_blocks: vector of decoded bits

        Andrew Smit November 2018
        """

        # Check block length
        if(len(codewords) % self.n or len(codewords) < self.n):
            raise ValueError('Error: Incomplete coded block in input array. Make sure coded input array length is a multiple of %d' %self.n)

        # Check input data type
        if(np.dtype(codewords[0]) != int):
            raise ValueError('Error: Input array should be int data type')

        # Calculate number of blocks
        Num_blocks = int(len(codewords) / self.n)

        decoded_blocks = np.zeros((Num_blocks,self.k),dtype=int)
        codewords = np.reshape(codewords,(Num_blocks,self.n))

        for p in range(Num_blocks):
            codeword = codewords[p,:]
            Ureg = np.zeros(self.n)
            S = np.zeros(len(self.G))
            decoded_bits = np.zeros(self.k)
            output = np.zeros(self.n)
            for i in range(0,self.n): # Switch A closed B open
                Ureg = np.roll(Ureg,1)
                Ureg[0] = codeword[i]
                S0temp = 0
                S[0] = codeword[i]
                for m in range(len(self.G)):
                    if(self.G[m] == '1'):
                        S0temp = S0temp + S[m]
                S0 = S
                S = np.roll(S,1)
                S[1] = S0temp % 2

            for i in range(0,self.n): # Switch B closed A open
                Stemp = 0
                for m in range(1,len(self.G)):
                    if(self.G[m] == '1'):
                        Stemp = Stemp + S[m]
                S = np.roll(S,1)
                S[1] = Stemp % 2
                and_out = 1
                for m in range(1,len(self.G)):
                    if(m > 1):
                        and_out = and_out and ((S[m]+1) % 2)
                    else:
                        and_out = and_out and S[m]
                output[i] = (and_out + Ureg[len(Ureg)-1]) % 2
                Ureg = np.roll(Ureg,1)
                Ureg[0] = 0
            decoded_bits = output[0:self.k].astype(int)
            decoded_blocks[p,:] = decoded_bits

        return np.reshape(decoded_blocks,np.size(decoded_blocks)).astype(int)


Instruction:
Can you create a Python 3 function that
selects the proper LockManager based on the current Celery backend.

Response:
def _select_manager(backend_name):
    """Select the proper LockManager based on the current backend used by Celery.

    :raise NotImplementedError: If Celery is using an unsupported backend.

    :param str backend_name: Class name of the current Celery backend. Usually value of
        current_app.extensions['celery'].celery.backend.__class__.__name__.

    :return: Class definition object (not instance). One of the _LockManager* classes.
    """
    if backend_name == 'RedisBackend':
        lock_manager = _LockManagerRedis
    elif backend_name == 'DatabaseBackend':
        lock_manager = _LockManagerDB
    else:
        raise NotImplementedError
    return lock_manager


Instruction:
Given the following Python 3 function, write the documentation
def single_instance(func=None, lock_timeout=None, include_args=False):
    if func is None:
        return partial(single_instance, lock_timeout=lock_timeout, include_args=include_args)

    @wraps(func)
    def wrapped(celery_self, *args, **kwargs):
        """Wrapped Celery task, for single_instance()."""
        # Select the manager and get timeout.
        timeout = (
            lock_timeout or celery_self.soft_time_limit or celery_self.time_limit
            or celery_self.app.conf.get('CELERYD_TASK_SOFT_TIME_LIMIT')
            or celery_self.app.conf.get('CELERYD_TASK_TIME_LIMIT')
            or (60 * 5)
        )
        manager_class = _select_manager(celery_self.backend.__class__.__name__)
        lock_manager = manager_class(celery_self, timeout, include_args, args, kwargs)

        # Lock and execute.
        with lock_manager:
            ret_value = func(*args, **kwargs)
        return ret_value
    return wrapped

Response: Decorator for celery tasks that allows a task to only have one running instance at a time.


Instruction:
Can you generate the documentation for the following Python 3 function
def task_identifier(self):
        task_id = self.celery_self.name
        if self.include_args:
            merged_args = str(self.args) + str([(k, self.kwargs[k]) for k in sorted(self.kwargs)])
            task_id += '.args.{0}'.format(hashlib.md5(merged_args.encode('utf-8')).hexdigest())
        return task_id

Response: Return the unique identifier of a task instance.


Instruction:
Can you implement a function in Python 3 that
returns True if lock exists and has not timed out.

Response:
def is_already_running(self):
        """Return True if lock exists and has not timed out."""
        redis_key = self.CELERY_LOCK.format(task_id=self.task_identifier)
        return self.celery_self.backend.client.exists(redis_key)


Instruction:
Make a summary of the following Python 3 code
def reset_lock(self):
        redis_key = self.CELERY_LOCK.format(task_id=self.task_identifier)
        self.celery_self.backend.client.delete(redis_key)

Response: Removes the lock regardless of timeout.


Instruction:
Write a Python 3 script to
return True if lock exists and has not timed out.

Response:
def is_already_running(self):
        """Return True if lock exists and has not timed out."""
        date_done = (self.restore_group(self.task_identifier) or dict()).get('date_done')
        if not date_done:
            return False
        difference = datetime.utcnow() - date_done
        return difference < timedelta(seconds=self.timeout)


Instruction:
Here you have a function in Python 3, explain what it does
def init_app(self, app):
        _state._register_app = self.original_register_app  # Restore Celery app registration function.
        if not hasattr(app, 'extensions'):
            app.extensions = dict()
        if 'celery' in app.extensions:
            raise ValueError('Already registered extension CELERY.')
        app.extensions['celery'] = _CeleryState(self, app)

        # Instantiate celery and read config.
        super(Celery, self).__init__(app.import_name, broker=app.config['CELERY_BROKER_URL'])

        # Set result backend default.
        if 'CELERY_RESULT_BACKEND' in app.config:
            self._preconf['CELERY_RESULT_BACKEND'] = app.config['CELERY_RESULT_BACKEND']

        self.conf.update(app.config)
        task_base = self.Task

        # Add Flask app context to celery instance.
        class ContextTask(task_base):
            def __call__(self, *_args, **_kwargs):
                with app.app_context():
                    return task_base.__call__(self, *_args, **_kwargs)
        setattr(ContextTask, 'abstract', True)
        setattr(self, 'Task', ContextTask)

Response: Initializes the Celery instance.


Instruction:
Make a summary of the following Python 3 code
def iter_chunksize(num_samples, chunksize):
    last_chunksize = int(np.mod(num_samples, chunksize))
    chunksize = int(chunksize)
    for _ in range(int(num_samples) // chunksize):
        yield chunksize
    if last_chunksize > 0:
        yield last_chunksize

Response: Iterator used to iterate over a array of size num_samples.


Instruction:
Can you tell what is the following Python 3 function doing
def iter_chunk_slice(num_samples, chunksize):
    i = 0
    for c_size in iter_chunksize(num_samples, chunksize):
        yield slice(i, i + c_size)
        i += c_size

Response: Iterator used to iterate over chunks over an array of size num_samples.


Instruction:
How would you explain what the following Python 3 function does
def iter_chunk_index(num_samples, chunksize):
    i = 0
    for c_size in iter_chunksize(num_samples, chunksize):
        yield i, i + c_size
        i += c_size

Response: Iterator used to iterate over a chunk of size num_samples.


Instruction:
How would you code a function in Python 3 to
reduce with func chunk by chunk.

Response:
def reduce_chunk(func, array):
    """Reduce with `func`, chunk by chunk, the passed pytable `array`.
    """
    res = []
    for slice in iter_chunk_slice(array.shape[-1], array.chunkshape[-1]):
        res.append(func(array[..., slice]))
    return func(res)


Instruction:
How would you implement a function in Python 3 that
maps with func chunk by chunk

Response:
def map_chunk(func, array, out_array):
    """Map with `func`, chunk by chunk, the input pytable `array`.
    The result is stored in the output pytable array `out_array`.
    """
    for slice in iter_chunk_slice(array.shape[-1], array.chunkshape[-1]):
        out_array.append(func(array[..., slice]))
    return out_array


Instruction:
Implement a Python 3 function for
generating timestamps from a set of remote simulations in dview.

Response:
def parallel_gen_timestamps(dview, max_em_rate, bg_rate):
    """Generate timestamps from a set of remote simulations in `dview`.
    Assumes that all the engines have an `S` object already containing
    an emission trace (`S.em`). The "photons" timestamps are generated
    from these emission traces and merged into a single array of timestamps.
    `max_em_rate` and `bg_rate` are passed to `S.sim_timetrace()`.
    """
    dview.execute('S.sim_timestamps_em_store(max_rate=%d, bg_rate=%d, '
                  'seed=S.EID, overwrite=True)' % (max_em_rate, bg_rate))
    dview.execute('times = S.timestamps[:]')
    dview.execute('times_par = S.timestamps_par[:]')
    Times = dview['times']
    Times_par = dview['times_par']
    # Assuming all t_max equal, just take the first
    t_max = dview['S.t_max'][0]
    t_tot = np.sum(dview['S.t_max'])
    dview.execute("sim_name = S.compact_name_core(t_max=False, hashdigit=0)")
    # Core names contains no ID or t_max
    sim_name = dview['sim_name'][0]
    times_all, times_par_all = merge_ph_times(Times, Times_par,
                                              time_block=t_max)
    return times_all, times_par_all, t_tot, sim_name


Instruction:
Make a summary of the following Python 3 code
def merge_ph_times(times_list, times_par_list, time_block):
    offsets = np.arange(len(times_list)) * time_block
    cum_sizes = np.cumsum([ts.size for ts in times_list])
    times = np.zeros(cum_sizes[-1])
    times_par = np.zeros(cum_sizes[-1], dtype='uint8')
    i1 = 0
    for i2, ts, ts_par, offset in zip(cum_sizes, times_list, times_par_list,
                                      offsets):
        times[i1:i2] = ts + offset
        times_par[i1:i2] = ts_par
        i1 = i2
    return times, times_par

Response: Build an array of timestamps joining the arrays in ph_times_list.


Instruction:
Write a Python 3 function for
returning a merged timestamp array for Donor + Accept. and bool mask for A.

Response:
def merge_DA_ph_times(ph_times_d, ph_times_a):
    """Returns a merged timestamp array for Donor+Accept. and bool mask for A.
    """
    ph_times = np.hstack([ph_times_d, ph_times_a])
    a_em = np.hstack([np.zeros(ph_times_d.size, dtype=np.bool),
                      np.ones(ph_times_a.size, dtype=np.bool)])
    index_sort = ph_times.argsort()
    return ph_times[index_sort], a_em[index_sort]


Instruction:
Create a Python 3 function to
return a simulation object summing the emissions and particles in SS.

Response:
def merge_particle_emission(SS):
    """Returns a sim object summing the emissions and particles in SS (list).
    """
    # Merge all the particles
    P = reduce(lambda x, y: x + y, [Si.particles for Si in SS])
    s = SS[0]
    S = ParticlesSimulation(t_step=s.t_step, t_max=s.t_max,
                            particles=P, box=s.box, psf=s.psf)
    S.em = np.zeros(s.em.shape, dtype=np.float64)
    for Si in SS:
        S.em += Si.em
    return S


Instruction:
Given the following Python 3 function, write the documentation
def load_PSFLab_file(fname):
    if os.path.exists(fname) or os.path.exists(fname + '.mat'):
        return loadmat(fname)['data']
    else:
        raise IOError("Can't find PSF file '%s'" % fname)

Response: Load the array data in the. mat file fname.


Instruction:
Here you have a function in Python 3, explain what it does
def convert_PSFLab_xz(data, x_step=0.5, z_step=0.5, normalize=False):
    z_len, x_len = data.shape
    hdata = data[:, (x_len - 1) // 2:]
    x = np.arange(hdata.shape[1]) * x_step
    z = np.arange(-(z_len - 1) / 2, (z_len - 1) / 2 + 1) * z_step
    if normalize:
        hdata /= hdata.max()  # normalize to 1 at peak
    return x, z, hdata, hdata[:, 0].argmax()

Response: Convert a 2D array containing a x - z PSF slice into a 2D array containing a x - z PSF slice.


Instruction:
Can you generate the documentation for the following Python 3 function
def eval(self, x, y, z):
        xc, yc, zc = self.rc
        sx, sy, sz = self.s

        ## Method1: direct evaluation
        #return exp(-(((x-xc)**2)/(2*sx**2) + ((y-yc)**2)/(2*sy**2) +\
        #        ((z-zc)**2)/(2*sz**2)))

        ## Method2: evaluation using numexpr
        def arg(s):
            return "((%s-%sc)**2)/(2*s%s**2)" % (s, s, s)
        return NE.evaluate("exp(-(%s + %s + %s))" %
                           (arg("x"), arg("y"), arg("z")))

Response: Evaluate the function in ( x y z.


Instruction:
How would you explain what the following Python 3 function does
def eval(self, x, y, z):
        ro = np.sqrt(x**2 + y**2)
        zs, xs = ro.shape
        v = self.eval_xz(ro.ravel(), z.ravel())
        return v.reshape(zs, xs)

Response: Evaluate the function in x y z.


Instruction:
Can you create a Python 3 function that
stores the PSF data in file_handle.

Response:
def to_hdf5(self, file_handle, parent_node='/'):
        """Store the PSF data in `file_handle` (pytables) in `parent_node`.

        The raw PSF array name is stored with same name as the original fname.
        Also, the following attribues are set: fname, dir_, x_step, z_step.
        """
        tarray = file_handle.create_array(parent_node, name=self.fname,
                                          obj=self.psflab_psf_raw,
                                          title='PSF x-z slice (PSFLab array)')
        for name in ['fname', 'dir_', 'x_step', 'z_step']:
            file_handle.set_node_attr(tarray, name, getattr(self, name))
        return tarray


Instruction:
Can you generate a brief explanation for the following Python 3 code
def hash(self):
        hash_list = []
        for key, value in sorted(self.__dict__.items()):
            if not callable(value):
                if isinstance(value, np.ndarray):
                    hash_list.append(value.tostring())
                else:
                    hash_list.append(str(value))
        return hashlib.md5(repr(hash_list).encode()).hexdigest()

Response: Return an md5 hash string computed on the PSF data.


Instruction:
Implement a Python 3 function for
checking whether the git executable is found.

Response:
def git_path_valid(git_path=None):
    """
    Check whether the git executable is found.
    """
    if git_path is None and GIT_PATH is None:
        return False
    if git_path is None: git_path = GIT_PATH
    try:
        call([git_path, '--version'])
        return True
    except OSError:
        return False


Instruction:
How would you explain what the following Python 3 function does
def get_git_version(git_path=None):
    if git_path is None: git_path = GIT_PATH
    git_version = check_output([git_path, "--version"]).split()[2]
    return git_version

Response: Get the Git version.


Instruction:
Can you tell what is the following Python 3 function doing
def check_clean_status(git_path=None):
    output = get_status(git_path)
    is_unmodified = (len(output.strip()) == 0)
    return is_unmodified

Response: Returns whether there are uncommitted changes in the working dir.


Instruction:
How would you explain what the following Python 3 function does
def get_last_commit_line(git_path=None):
    if git_path is None: git_path = GIT_PATH
    output = check_output([git_path, "log", "--pretty=format:'%ad %h %s'",
                           "--date=short", "-n1"])
    return output.strip()[1:-1]

Response: Get one - line description of HEAD commit for current dir.


Instruction:
Write a Python 3 function that can
get the last commit SHA1 of the current git repository.

Response:
def get_last_commit(git_path=None):
    """
    Get the HEAD commit SHA1 of repository in current dir.
    """
    if git_path is None: git_path = GIT_PATH
    line = get_last_commit_line(git_path)
    revision_id = line.split()[1]
    return revision_id


Instruction:
Write a Python 3 function that can
print the summary of the current version of the current revision.

Response:
def print_summary(string='Repository', git_path=None):
    """
    Print the last commit line and eventual uncommitted changes.
    """
    if git_path is None: git_path = GIT_PATH

    # If git is available, check fretbursts version
    if not git_path_valid():
        print('\n%s revision unknown (git not found).' % string)
    else:
        last_commit = get_last_commit_line()
        print('\n{} revision:\n {}\n'.format(string, last_commit))
        if not check_clean_status():
            print('\nWARNING -> Uncommitted changes:')
            print(get_status())


Instruction:
Implement a Python 3 function for
getting the filenames for donor and acceptor timestamps for the given parameters

Response:
def get_bromo_fnames_da(d_em_kHz, d_bg_kHz, a_em_kHz, a_bg_kHz,
        ID='1+2+3+4+5+6', t_tot='480', num_p='30', pM='64',
        t_step=0.5e-6, D=1.2e-11, dir_=''):
    """Get filenames for donor and acceptor timestamps for the given parameters
    """

    clk_p = t_step/32. # with t_step=0.5us -> 156.25 ns
    E_sim = 1.*a_em_kHz/(a_em_kHz + d_em_kHz)

    FRET_val = 100.*E_sim
    print("Simulated FRET value: %.1f%%" % FRET_val)

    d_em_kHz_str = "%04d" % d_em_kHz
    a_em_kHz_str = "%04d" % a_em_kHz
    d_bg_kHz_str = "%04.1f" % d_bg_kHz
    a_bg_kHz_str = "%04.1f" % a_bg_kHz

    print("D: EM %s BG %s " % (d_em_kHz_str, d_bg_kHz_str))
    print("A: EM %s BG %s " % (a_em_kHz_str, a_bg_kHz_str))

    fname_d = ('ph_times_{t_tot}s_D{D}_{np}P_{pM}pM_'
               'step{ts_us}us_ID{ID}_EM{em}kHz_BG{bg}kHz.npy').format(
                       em=d_em_kHz_str, bg=d_bg_kHz_str, t_tot=t_tot, pM=pM,
                       np=num_p, ID=ID, ts_us=t_step*1e6, D=D)

    fname_a = ('ph_times_{t_tot}s_D{D}_{np}P_{pM}pM_'
               'step{ts_us}us_ID{ID}_EM{em}kHz_BG{bg}kHz.npy').format(
                       em=a_em_kHz_str, bg=a_bg_kHz_str, t_tot=t_tot, pM=pM,
                       np=num_p, ID=ID, ts_us=t_step*1e6, D=D)
    print(fname_d)
    print(fname_a)

    name = ('BroSim_E{:.1f}_dBG{:.1f}k_aBG{:.1f}k_'
            'dEM{:.0f}k').format(FRET_val, d_bg_kHz, a_bg_kHz, d_em_kHz)

    return dir_+fname_d, dir_+fname_a, name, clk_p, E_sim


Instruction:
Create a Python 3 function for
storing parameters in params in ParticlesSimulation

Response:
def set_sim_params(self, nparams, attr_params):
        """Store parameters in `params` in `h5file.root.parameters`.

        `nparams` (dict)
            A dict as returned by `get_params()` in `ParticlesSimulation()`
            The format is:
            keys:
                used as parameter name
            values: (2-elements tuple)
                first element is the parameter value
                second element is a string used as "title" (description)
        `attr_params` (dict)
            A dict whole items are stored as attributes in '/parameters'
        """
        for name, value in nparams.items():
            val = value[0] if value[0] is not None else 'none'
            self.h5file.create_array('/parameters', name, obj=val,
                                     title=value[1])
        for name, value in attr_params.items():
            self.h5file.set_node_attr('/parameters', name, value)


Instruction:
Given the following Python 3 function, write the documentation
def numeric_params(self):
        nparams = dict()
        for p in self.h5file.root.parameters:
            nparams[p.name] = p.read()
        return nparams

Response: Return a dict containing all numeric parameters stored in '/parameters'


Instruction:
Can you generate a brief explanation for the following Python 3 code
def numeric_params_meta(self):
        nparams = dict()
        for p in self.h5file.root.parameters:
            nparams[p.name] = (p.read(), p.title)
        return nparams

Response: Return a dict with all parameters and metadata in '/parameters'.


Instruction:
Can you implement a function in Python 3 that
adds a trajectory to the HDF5 file.

Response:
def add_trajectory(self, name, overwrite=False, shape=(0,), title='',
                       chunksize=2**19, comp_filter=default_compression,
                       atom=tables.Float64Atom(), params=dict(),
                       chunkslice='bytes'):
        """Add an trajectory array in '/trajectories'.
        """
        group = self.h5file.root.trajectories
        if name in group:
            print("%s already exists ..." % name, end='')
            if overwrite:
                self.h5file.remove_node(group, name)
                print(" deleted.")
            else:
                print(" old returned.")
                return group.get_node(name)

        nparams = self.numeric_params
        num_t_steps = nparams['t_max'] / nparams['t_step']

        chunkshape = self.calc_chunkshape(chunksize, shape, kind=chunkslice)
        store_array = self.h5file.create_earray(
            group, name, atom=atom,
            shape = shape,
            chunkshape = chunkshape,
            expectedrows = num_t_steps,
            filters = comp_filter,
            title = title)

        # Set the array parameters/attributes
        for key, value in params.items():
            store_array.set_attr(key, value)
        store_array.set_attr('PyBroMo', __version__)
        store_array.set_attr('creation_time', current_time())
        return store_array


Instruction:
Given the following Python 3 function, write the documentation
def add_emission_tot(self, chunksize=2**19, comp_filter=default_compression,
                         overwrite=False, params=dict(),
                         chunkslice='bytes'):
        """Add the `emission_tot` array in '/trajectories'.
        """
        kwargs = dict(overwrite=overwrite, chunksize=chunksize, params=params,
                      comp_filter=comp_filter, atom=tables.Float32Atom(),
                      title='Summed emission trace of all the particles')
        return self.add_trajectory('emission_tot', **kwargs)

Response: Add the emission_tot array in '/trajectories.


Instruction:
Given the following Python 3 function, write the documentation
def add_emission(self, chunksize=2**19, comp_filter=default_compression,
                     overwrite=False, params=dict(), chunkslice='bytes'):
        """Add the `emission` array in '/trajectories'.
        """
        nparams = self.numeric_params
        num_particles = nparams['np']

        return self.add_trajectory('emission', shape=(num_particles, 0),
                                   overwrite=overwrite, chunksize=chunksize,
                                   comp_filter=comp_filter,
                                   atom=tables.Float32Atom(),
                                   title='Emission trace of each particle',
                                   params=params)

Response: Add the emission array in '/trajectories.


Instruction:
Given the following Python 3 function, write the documentation
def add_position(self, radial=False, chunksize=2**19, chunkslice='bytes',
                     comp_filter=default_compression, overwrite=False,
                     params=dict()):
        """Add the `position` array in '/trajectories'.
        """
        nparams = self.numeric_params
        num_particles = nparams['np']

        name, ncoords, prefix = 'position', 3, 'X-Y-Z'
        if radial:
            name, ncoords, prefix = 'position_rz', 2, 'R-Z'
        title = '%s position trace of each particle' % prefix
        return self.add_trajectory(name, shape=(num_particles, ncoords, 0),
                                   overwrite=overwrite, chunksize=chunksize,
                                   comp_filter=comp_filter,
                                   atom=tables.Float32Atom(),
                                   title=title,
                                   params=params)

Response: Add the position array in '/trajectories.


Instruction:
How would you implement a function in Python 3 that
folds all the values of a outside a1.. a2 inside that interval.

Response:
def wrap_periodic(a, a1, a2):
    """Folds all the values of `a` outside [a1..a2] inside that interval.
    This function is used to apply periodic boundary conditions.
    """
    a -= a1
    wrapped = np.mod(a, a2 - a1) + a1
    return wrapped


Instruction:
How would you explain what the following Python 3 function does
def wrap_mirror(a, a1, a2):
    a[a > a2] = a2 - (a[a > a2] - a2)
    a[a < a1] = a1 + (a1 - a[a < a1])
    return a

Response: Folds all the values of a outside a1.. a2 inside that interval.


Instruction:
Here you have a function in Python 3, explain what it does
def sim_timetrace(emission, max_rate, t_step):
    emission_rates = emission * max_rate * t_step
    return np.random.poisson(lam=emission_rates).astype(np.uint8)

Response: Draw random emitted photons from Poisson


Instruction:
Can you tell what is the following Python 3 function doing
def sim_timetrace_bg(emission, max_rate, bg_rate, t_step, rs=None):
    if rs is None:
        rs = np.random.RandomState()
    em = np.atleast_2d(emission).astype('float64', copy=False)
    counts_nrows = em.shape[0]
    if bg_rate is not None:
        counts_nrows += 1   # add a row for poisson background
    counts = np.zeros((counts_nrows, em.shape[1]), dtype='u1')
    # In-place computation
    # NOTE: the caller will see the modification
    em *= (max_rate * t_step)
    # Use automatic type conversion int64 (counts_par) -> uint8 (counts)
    counts_par = rs.poisson(lam=em)
    if bg_rate is None:
        counts[:] = counts_par
    else:
        counts[:-1] = counts_par
        counts[-1] = rs.poisson(lam=bg_rate * t_step, size=em.shape[1])
    return counts

Response: Draw random emissions from r. v. ~ Poisson background.


Instruction:
Create a Python 3 function for
drawing random emitted photons from r. v. ~ Poisson ( emission_rates ).

Response:
def sim_timetrace_bg2(emission, max_rate, bg_rate, t_step, rs=None):
    """Draw random emitted photons from r.v. ~ Poisson(emission_rates).

    This is an alternative implementation of :func:`sim_timetrace_bg`.
    """
    if rs is None:
        rs = np.random.RandomState()
    emiss_bin_rate = np.zeros((emission.shape[0] + 1, emission.shape[1]),
                              dtype='float64')
    emiss_bin_rate[:-1] = emission * max_rate * t_step
    if bg_rate is not None:
        emiss_bin_rate[-1] = bg_rate * t_step
        counts = rs.poisson(lam=emiss_bin_rate).astype('uint8')
    else:
        counts = rs.poisson(lam=emiss_bin_rate[:-1]).astype('uint8')
    return counts


Instruction:
Explain what the following Python 3 code does
def volume(self):
        return (self.x2 - self.x1) * (self.y2 - self.y1) * (self.z2 - self.z1)

Response: Box volume in m^3.


Instruction:
How would you code a function in Python 3 to
generate a list of Particles.

Response:
def _generate(num_particles, D, box, rs):
        """Generate a list of `Particle` objects."""
        X0 = rs.rand(num_particles) * (box.x2 - box.x1) + box.x1
        Y0 = rs.rand(num_particles) * (box.y2 - box.y1) + box.y1
        Z0 = rs.rand(num_particles) * (box.z2 - box.z1) + box.z1
        return [Particle(D=D, x0=x0, y0=y0, z0=z0)
                for x0, y0, z0 in zip(X0, Y0, Z0)]


Instruction:
Create a Python 3 function for
adding particles with diffusion coefficient D at random positions.

Response:
def add(self, num_particles, D):
        """Add particles with diffusion coefficient `D` at random positions.
        """
        self._plist += self._generate(num_particles, D, box=self.box,
                                      rs=self.rs)


Instruction:
Explain what the following Python 3 code does
def positions(self):
        return np.vstack([p.r0 for p in self]).reshape(len(self), 3, 1)

Response: Initial position for each particle. Shape N 3 1.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def diffusion_coeff_counts(self):
        return [(key, len(list(group)))
                for key, group in itertools.groupby(self.diffusion_coeff)]

Response: List of tuples of diffusion coefficient counts pairs.


Instruction:
Can you generate the documentation for the following Python 3 function
def datafile_from_hash(hash_, prefix, path):
        pattern = '%s_%s*.h*' % (prefix, hash_)
        datafiles = list(path.glob(pattern))
        if len(datafiles) == 0:
            raise NoMatchError('No matches for "%s"' % pattern)
        if len(datafiles) > 1:
            raise MultipleMatchesError('More than 1 match for "%s"' % pattern)
        return datafiles[0]

Response: Return pathlib. Path for a data - file with given hash and prefix.


Instruction:
Make a summary of the following Python 3 code
def from_datafile(hash_, path='./', ignore_timestamps=False, mode='r'):
        path = Path(path)
        assert path.exists()

        file_traj = ParticlesSimulation.datafile_from_hash(
            hash_, prefix=ParticlesSimulation._PREFIX_TRAJ, path=path)
        store = TrajectoryStore(file_traj, mode='r')

        psf_pytables = store.h5file.get_node('/psf/default_psf')
        psf = NumericPSF(psf_pytables=psf_pytables)
        box = store.h5file.get_node_attr('/parameters', 'box')
        P = store.h5file.get_node_attr('/parameters', 'particles')

        names = ['t_step', 't_max', 'EID', 'ID']
        kwargs = {name: store.numeric_params[name] for name in names}
        S = ParticlesSimulation(particles=Particles.from_json(P), box=box,
                                psf=psf, **kwargs)

        # Emulate S.open_store_traj()
        S.store = store
        S.psf_pytables = psf_pytables
        S.traj_group = S.store.h5file.root.trajectories
        S.emission = S.traj_group.emission
        S.emission_tot = S.traj_group.emission_tot
        if 'position' in S.traj_group:
            S.position = S.traj_group.position
        elif 'position_rz' in S.traj_group:
            S.position = S.traj_group.position_rz
        S.chunksize = S.store.h5file.get_node('/parameters', 'chunksize')
        if not ignore_timestamps:
            try:
                file_ts = ParticlesSimulation.datafile_from_hash(
                    hash_, prefix=ParticlesSimulation._PREFIX_TS, path=path)
            except NoMatchError:
                # There are no timestamps saved.
                pass
            else:
                # Load the timestamps
                S.ts_store = TimestampStore(file_ts, mode=mode)
                S.ts_group = S.ts_store.h5file.root.timestamps
                print(' - Found matching timestamps.')
        return S

Response: Load simulation from disk trajectories and timestamps.


Instruction:
Can you tell what is the following Python 3 function doing
def _get_group_randomstate(rs, seed, group):
        if rs is None:
            rs = np.random.RandomState(seed=seed)
            # Try to set the random state from the last session to preserve
            # a single random stream when simulating timestamps multiple times
            if 'last_random_state' in group._v_attrs:
                rs.set_state(group._v_attrs['last_random_state'])
                print("INFO: Random state set to last saved state in '%s'." %
                      group._v_name)
            else:
                print("INFO: Random state initialized from seed (%d)." % seed)
        return rs

Response: Return a RandomState equal to the input unless rs is None.


Instruction:
Can you write a function in Python 3 where it
returns an md5 hash for the simulation parameters

Response:
def hash(self):
        """Return an hash for the simulation parameters (excluding ID and EID)
        This can be used to generate unique file names for simulations
        that have the same parameters and just different ID or EID.
        """
        hash_numeric = 't_step=%.3e, t_max=%.2f, np=%d, conc=%.2e' % \
            (self.t_step, self.t_max, self.num_particles, self.concentration())
        hash_list = [hash_numeric, self.particles.short_repr(), repr(self.box),
                     self.psf.hash()]
        return hashlib.md5(repr(hash_list).encode()).hexdigest()


Instruction:
Write a Python 3 script for
compacting representation of simulation params.

Response:
def compact_name_core(self, hashsize=6, t_max=False):
        """Compact representation of simulation params (no ID, EID and t_max)
        """
        Moles = self.concentration()
        name = "%s_%dpM_step%.1fus" % (
            self.particles.short_repr(), Moles * 1e12, self.t_step * 1e6)
        if hashsize > 0:
            name = self.hash()[:hashsize] + '_' + name
        if t_max:
            name += "_t_max%.1fs" % self.t_max
        return name


Instruction:
Create a Python 3 function for
compacting representation of all simulation parameters

Response:
def compact_name(self, hashsize=6):
        """Compact representation of all simulation parameters
        """
        # this can be made more robust for ID > 9 (double digit)
        s = self.compact_name_core(hashsize, t_max=True)
        s += "_ID%d-%d" % (self.ID, self.EID)
        return s


Instruction:
Implement a Python 3 function for
printing on - disk array sizes required for current set of parameters.

Response:
def print_sizes(self):
        """Print on-disk array sizes required for current set of parameters."""
        float_size = 4
        MB = 1024 * 1024
        size_ = self.n_samples * float_size
        em_size = size_ * self.num_particles / MB
        pos_size = 3 * size_ * self.num_particles / MB
        print("  Number of particles:", self.num_particles)
        print("  Number of time steps:", self.n_samples)
        print("  Emission array - 1 particle (float32): %.1f MB" % (size_ / MB))
        print("  Emission array (float32): %.1f MB" % em_size)
        print("  Position array (float32): %.1f MB " % pos_size)


Instruction:
Can you implement a function in Python 3 that
returns the concentration of the particles in the box.

Response:
def concentration(self, pM=False):
        """Return the concentration (in Moles) of the particles in the box.
        """
        concentr = (self.num_particles / NA) / self.box.volume_L
        if pM:
            concentr *= 1e12
        return concentr


Instruction:
Make a summary of the following Python 3 code
def _sim_trajectories(self, time_size, start_pos, rs,
                          total_emission=False, save_pos=False, radial=False,
                          wrap_func=wrap_periodic):
        """Simulate (in-memory) `time_size` steps of trajectories.

        Simulate Brownian motion diffusion and emission of all the particles.
        Uses the attributes: num_particles, sigma_1d, box, psf.

        Arguments:
            time_size (int): number of time steps to be simulated.
            start_pos (array): shape (num_particles, 3), particles start
                positions. This array is modified to store the end position
                after this method is called.
            rs (RandomState): a `numpy.random.RandomState` object used
                to generate the random numbers.
            total_emission (bool): if True, store only the total emission array
                containing the sum of emission of all the particles.
            save_pos (bool): if True, save the particles 3D trajectories
            wrap_func (function): the function used to apply the boundary
                condition (use :func:`wrap_periodic` or :func:`wrap_mirror`).

        Returns:
            POS (list): list of 3D trajectories arrays (3 x time_size)
            em (array): array of emission (total or per-particle)
        """
        time_size = int(time_size)
        num_particles = self.num_particles
        if total_emission:
            em = np.zeros(time_size, dtype=np.float32)
        else:
            em = np.zeros((num_particles, time_size), dtype=np.float32)

        POS = []
        # pos_w = np.zeros((3, c_size))
        for i, sigma_1d in enumerate(self.sigma_1d):
            delta_pos = rs.normal(loc=0, scale=sigma_1d,
                                  size=3 * time_size)
            delta_pos = delta_pos.reshape(3, time_size)
            pos = np.cumsum(delta_pos, axis=-1, out=delta_pos)
            pos += start_pos[i]

            # Coordinates wrapping using the specified boundary conditions
            for coord in (0, 1, 2):
                pos[coord] = wrap_func(pos[coord], *self.box.b[coord])

            # Sample the PSF along i-th trajectory then square to account
            # for emission and detection PSF.
            Ro = sqrt(pos[0]**2 + pos[1]**2)  # radial pos. on x-y plane
            Z = pos[2]
            current_em = self.psf.eval_xz(Ro, Z)**2
            if total_emission:
                # Add the current particle emission to the total emission
                em += current_em.astype(np.float32)
            else:
                # Store the individual emission of current particle
                em[i] = current_em.astype(np.float32)
            if save_pos:
                pos_save = np.vstack((Ro, Z)) if radial else pos
                POS.append(pos_save[np.newaxis, :, :])
            # Update start_pos in-place for current particle
            start_pos[i] = pos[:, -1:]
        return POS, em

Response: Simulate the trajectories of all particles.


Instruction:
Explain what the following Python 3 code does
def simulate_diffusion(self, save_pos=False, total_emission=True,
                           radial=False, rs=None, seed=1, path='./',
                           wrap_func=wrap_periodic,
                           chunksize=2**19, chunkslice='times', verbose=True):
        """Simulate Brownian motion trajectories and emission rates.

        This method performs the Brownian motion simulation using the current
        set of parameters. Before running this method you can check the
        disk-space requirements using :method:`print_sizes`.

        Results are stored to disk in HDF5 format and are accessible in
        in `self.emission`, `self.emission_tot` and `self.position` as
        pytables arrays.

        Arguments:
            save_pos (bool): if True, save the particles 3D trajectories
            total_emission (bool): if True, store only the total emission array
                containing the sum of emission of all the particles.
            rs (RandomState object): random state object used as random number
                generator. If None, use a random state initialized from seed.
            seed (uint): when `rs` is None, `seed` is used to initialize the
                random state, otherwise is ignored.
            wrap_func (function): the function used to apply the boundary
                condition (use :func:`wrap_periodic` or :func:`wrap_mirror`).
            path (string): a folder where simulation data is saved.
            verbose (bool): if False, prints no output.
        """
        if rs is None:
            rs = np.random.RandomState(seed=seed)
        self.open_store_traj(chunksize=chunksize, chunkslice=chunkslice,
                             radial=radial, path=path)
        # Save current random state for reproducibility
        self.traj_group._v_attrs['init_random_state'] = rs.get_state()

        em_store = self.emission_tot if total_emission else self.emission

        print('- Start trajectories simulation - %s' % ctime(), flush=True)
        if verbose:
            print('[PID %d] Diffusion time:' % os.getpid(), end='')
        i_chunk = 0
        t_chunk_size = self.emission.chunkshape[1]
        chunk_duration = t_chunk_size * self.t_step

        par_start_pos = self.particles.positions
        prev_time = 0
        for time_size in iter_chunksize(self.n_samples, t_chunk_size):
            if verbose:
                curr_time = int(chunk_duration * (i_chunk + 1))
                if curr_time > prev_time:
                    print(' %ds' % curr_time, end='', flush=True)
                    prev_time = curr_time

            POS, em = self._sim_trajectories(time_size, par_start_pos, rs,
                                             total_emission=total_emission,
                                             save_pos=save_pos, radial=radial,
                                             wrap_func=wrap_func)

            ## Append em to the permanent storage
            # if total_emission, data is just a linear array
            # otherwise is a 2-D array (self.num_particles, c_size)
            em_store.append(em)
            if save_pos:
                self.position.append(np.vstack(POS).astype('float32'))
            i_chunk += 1
            self.store.h5file.flush()

        # Save current random state
        self.traj_group._v_attrs['last_random_state'] = rs.get_state()
        self.store.h5file.flush()
        print('\n- End trajectories simulation - %s' % ctime(), flush=True)

Response: This method simulates the diffusion of the current trajectory and the emission rates.


Instruction:
How would you explain what the following Python 3 function does
def get_timestamps_part(self, name):
        par_name = name + '_par'
        timestamps = self.ts_store.h5file.get_node('/timestamps', name)
        particles = self.ts_store.h5file.get_node('/timestamps', par_name)
        return timestamps, particles

Response: Return matching timestamps and particles pytables arrays.


Instruction:
Can you implement a function in Python 3 that
simulates timestamps from emission trajectories.

Response:
def _sim_timestamps(self, max_rate, bg_rate, emission, i_start, rs,
                        ip_start=0, scale=10, sort=True):
        """Simulate timestamps from emission trajectories.

        Uses attributes: `.t_step`.

        Returns:
            A tuple of two arrays: timestamps and particles.
        """
        counts_chunk = sim_timetrace_bg(emission, max_rate, bg_rate,
                                        self.t_step, rs=rs)
        nrows = emission.shape[0]
        if bg_rate is not None:
            nrows += 1
        assert counts_chunk.shape == (nrows, emission.shape[1])
        max_counts = counts_chunk.max()
        if max_counts == 0:
            return np.array([], dtype=np.int64), np.array([], dtype=np.int64)

        time_start = i_start * scale
        time_stop = time_start + counts_chunk.shape[1] * scale
        ts_range = np.arange(time_start, time_stop, scale, dtype='int64')

        # Loop for each particle to compute timestamps
        times_chunk_p = []
        par_index_chunk_p = []
        for ip, counts_chunk_ip in enumerate(counts_chunk):
            # Compute timestamps for particle ip for all bins with counts
            times_c_ip = []
            for v in range(1, max_counts + 1):
                times_c_ip.append(ts_range[counts_chunk_ip >= v])

            # Stack the timestamps from different "counts"
            t = np.hstack(times_c_ip)
            # Append current particle
            times_chunk_p.append(t)
            par_index_chunk_p.append(np.full(t.size, ip + ip_start, dtype='u1'))

        # Merge the arrays of different particles
        times_chunk = np.hstack(times_chunk_p)
        par_index_chunk = np.hstack(par_index_chunk_p)

        if sort:
            # Sort timestamps inside the merged chunk
            index_sort = times_chunk.argsort(kind='mergesort')
            times_chunk = times_chunk[index_sort]
            par_index_chunk = par_index_chunk[index_sort]

        return times_chunk, par_index_chunk


Instruction:
Can you generate the documentation for the following Python 3 function
def simulate_timestamps_mix(self, max_rates, populations, bg_rate,
                                rs=None, seed=1, chunksize=2**16,
                                comp_filter=None, overwrite=False,
                                skip_existing=False, scale=10,
                                path=None, t_chunksize=None, timeslice=None):
        """Compute one timestamps array for a mixture of N populations.

        Timestamp data are saved to disk and accessible as pytables arrays in
        `._timestamps` and `._tparticles`.
        The background generated timestamps are assigned a
        conventional particle number (last particle index + 1).

        Arguments:
            max_rates (list): list of the peak max emission rate for each
                population.
            populations (list of slices): slices to `self.particles`
                defining each population.
            bg_rate (float, cps): rate for a Poisson background process
            rs (RandomState object): random state object used as random number
                generator. If None, use a random state initialized from seed.
            seed (uint): when `rs` is None, `seed` is used to initialize the
                random state, otherwise is ignored.
            chunksize (int): chunk size used for the on-disk timestamp array
            comp_filter (tables.Filter or None): compression filter to use
                for the on-disk `timestamps` and `tparticles` arrays.
                If None use default compression.
            overwrite (bool): if True, overwrite any pre-existing timestamps
                array. If False, never overwrite. The outcome of simulating an
                existing array is controlled by `skip_existing` flag.
            skip_existing (bool): if True, skip simulation if the same
                timestamps array is already present.
            scale (int): `self.t_step` is multiplied by `scale` to obtain the
                timestamps units in seconds.
            path (string): folder where to save the data.
            timeslice (float or None): timestamps are simulated until
                `timeslice` seconds. If None, simulate until `self.t_max`.
        """
        self.open_store_timestamp(chunksize=chunksize, path=path)
        rs = self._get_group_randomstate(rs, seed, self.ts_group)
        if t_chunksize is None:
            t_chunksize = self.emission.chunkshape[1]
        timeslice_size = self.n_samples
        if timeslice is not None:
            timeslice_size = timeslice // self.t_step

        name = self._get_ts_name_mix(max_rates, populations, bg_rate, rs=rs)
        kw = dict(name=name, clk_p=self.t_step / scale,
                  max_rates=max_rates, bg_rate=bg_rate, populations=populations,
                  num_particles=self.num_particles,
                  bg_particle=self.num_particles,
                  overwrite=overwrite, chunksize=chunksize)
        if comp_filter is not None:
            kw.update(comp_filter=comp_filter)
        try:
            self._timestamps, self._tparticles = (self.ts_store
                                                  .add_timestamps(**kw))
        except ExistingArrayError as e:
            if skip_existing:
                print(' - Skipping already present timestamps array.')
                return
            else:
                raise e

        self.ts_group._v_attrs['init_random_state'] = rs.get_state()
        self._timestamps.attrs['init_random_state'] = rs.get_state()
        self._timestamps.attrs['PyBroMo'] = __version__

        ts_list, part_list = [], []
        # Load emission in chunks, and save only the final timestamps
        bg_rates = [None] * (len(max_rates) - 1) + [bg_rate]
        prev_time = 0
        for i_start, i_end in iter_chunk_index(timeslice_size, t_chunksize):

            curr_time = np.around(i_start * self.t_step, decimals=0)
            if curr_time > prev_time:
                print(' %.1fs' % curr_time, end='', flush=True)
                prev_time = curr_time

            em_chunk = self.emission[:, i_start:i_end]

            times_chunk_s, par_index_chunk_s = \
                self._sim_timestamps_populations(
                    em_chunk, max_rates, populations, bg_rates, i_start,
                    rs, scale)

            # Save sorted timestamps (suffix '_s') and corresponding particles
            ts_list.append(times_chunk_s)
            part_list.append(par_index_chunk_s)

        for ts, part in zip(ts_list, part_list):
            self._timestamps.append(ts)
            self._tparticles.append(part)

        # Save current random state so it can be resumed in the next session
        self.ts_group._v_attrs['last_random_state'] = rs.get_state()
        self._timestamps.attrs['last_random_state'] = rs.get_state()
        self.ts_store.h5file.flush()

Response: Simulate timestamps for a mixture of N populations.


Instruction:
Can you generate the documentation for the following Python 3 function
def simulate_timestamps_mix_da(self, max_rates_d, max_rates_a,
                                   populations, bg_rate_d, bg_rate_a,
                                   rs=None, seed=1, chunksize=2**16,
                                   comp_filter=None, overwrite=False,
                                   skip_existing=False, scale=10,
                                   path=None, t_chunksize=2**19,
                                   timeslice=None):

        """Compute D and A timestamps arrays for a mixture of N populations.

        This method reads the emission from disk once, and generates a pair
        of timestamps arrays (e.g. donor and acceptor) from each chunk.

        Timestamp data are saved to disk and accessible as pytables arrays in
        `._timestamps_d/a` and `._tparticles_d/a`.
        The background generated timestamps are assigned a
        conventional particle number (last particle index + 1).

        Arguments:
            max_rates_d (list): list of the peak max emission rate in the
                donor channel for each population.
            max_rates_a (list): list of the peak max emission rate in the
                acceptor channel for each population.
            populations (list of slices): slices to `self.particles`
                defining each population.
            bg_rate_d (float, cps): rate for a Poisson background process
                in the donor channel.
            bg_rate_a (float, cps): rate for a Poisson background process
                in the acceptor channel.
            rs (RandomState object): random state object used as random number
                generator. If None, use a random state initialized from seed.
            seed (uint): when `rs` is None, `seed` is used to initialize the
                random state, otherwise is ignored.
            chunksize (int): chunk size used for the on-disk timestamp array
            comp_filter (tables.Filter or None): compression filter to use
                for the on-disk `timestamps` and `tparticles` arrays.
                If None use default compression.
            overwrite (bool): if True, overwrite any pre-existing timestamps
                array. If False, never overwrite. The outcome of simulating an
                existing array is controlled by `skip_existing` flag.
            skip_existing (bool): if True, skip simulation if the same
                timestamps array is already present.
            scale (int): `self.t_step` is multiplied by `scale` to obtain the
                timestamps units in seconds.
            path (string): folder where to save the data.
            timeslice (float or None): timestamps are simulated until
                `timeslice` seconds. If None, simulate until `self.t_max`.
        """
        self.open_store_timestamp(chunksize=chunksize, path=path)
        rs = self._get_group_randomstate(rs, seed, self.ts_group)
        if t_chunksize is None:
            t_chunksize = self.emission.chunkshape[1]
        timeslice_size = self.n_samples
        if timeslice is not None:
            timeslice_size = timeslice // self.t_step

        name_d = self._get_ts_name_mix(max_rates_d, populations, bg_rate_d, rs)
        name_a = self._get_ts_name_mix(max_rates_a, populations, bg_rate_a, rs)

        kw = dict(clk_p=self.t_step / scale,
                  populations=populations,
                  num_particles=self.num_particles,
                  bg_particle=self.num_particles,
                  overwrite=overwrite, chunksize=chunksize)
        if comp_filter is not None:
            kw.update(comp_filter=comp_filter)

        kw.update(name=name_d, max_rates=max_rates_d, bg_rate=bg_rate_d)
        try:
            self._timestamps_d, self._tparticles_d = (self.ts_store
                                                      .add_timestamps(**kw))
        except ExistingArrayError as e:
            if skip_existing:
                print(' - Skipping already present timestamps array.')
                return
            else:
                raise e

        kw.update(name=name_a, max_rates=max_rates_a, bg_rate=bg_rate_a)
        try:
            self._timestamps_a, self._tparticles_a = (self.ts_store
                                                      .add_timestamps(**kw))
        except ExistingArrayError as e:
            if skip_existing:
                print(' - Skipping already present timestamps array.')
                return
            else:
                raise e

        self.ts_group._v_attrs['init_random_state'] = rs.get_state()
        self._timestamps_d.attrs['init_random_state'] = rs.get_state()
        self._timestamps_d.attrs['PyBroMo'] = __version__
        self._timestamps_a.attrs['init_random_state'] = rs.get_state()
        self._timestamps_a.attrs['PyBroMo'] = __version__

        # Load emission in chunks, and save only the final timestamps
        bg_rates_d = [None] * (len(max_rates_d) - 1) + [bg_rate_d]
        bg_rates_a = [None] * (len(max_rates_a) - 1) + [bg_rate_a]
        prev_time = 0
        for i_start, i_end in iter_chunk_index(timeslice_size, t_chunksize):

            curr_time = np.around(i_start * self.t_step, decimals=1)
            if curr_time > prev_time:
                print(' %.1fs' % curr_time, end='', flush=True)
                prev_time = curr_time

            em_chunk = self.emission[:, i_start:i_end]

            times_chunk_s_d, par_index_chunk_s_d = \
                self._sim_timestamps_populations(
                    em_chunk, max_rates_d, populations, bg_rates_d, i_start,
                    rs, scale)

            times_chunk_s_a, par_index_chunk_s_a = \
                self._sim_timestamps_populations(
                    em_chunk, max_rates_a, populations, bg_rates_a, i_start,
                    rs, scale)

            # Save sorted timestamps (suffix '_s') and corresponding particles
            self._timestamps_d.append(times_chunk_s_d)
            self._tparticles_d.append(par_index_chunk_s_d)
            self._timestamps_a.append(times_chunk_s_a)
            self._tparticles_a.append(par_index_chunk_s_a)

        # Save current random state so it can be resumed in the next session
        self.ts_group._v_attrs['last_random_state'] = rs.get_state()
        self._timestamps_d._v_attrs['last_random_state'] = rs.get_state()
        self.ts_store.h5file.flush()

Response: This method reads the timestamps from disk and generates the timestamps arrays for a mixture of N populations.


Instruction:
Can you generate the documentation for the following Python 3 function
def merge_da(ts_d, ts_par_d, ts_a, ts_par_a):
    ts = np.hstack([ts_d, ts_a])
    ts_par = np.hstack([ts_par_d, ts_par_a])
    a_ch = np.hstack([np.zeros(ts_d.shape[0], dtype=bool),
                      np.ones(ts_a.shape[0], dtype=bool)])
    index_sort = ts.argsort()
    return ts[index_sort], a_ch[index_sort], ts_par[index_sort]

Response: Merge donor and acceptor timestamps and particle arrays.


Instruction:
Create a Python 3 function to
compute donor and acceptor emission rates from total emission rate and E.

Response:
def em_rates_from_E_DA(em_rate_tot, E_values):
    """Donor and Acceptor emission rates from total emission rate and E (FRET).
    """
    E_values = np.asarray(E_values)
    em_rates_a = E_values * em_rate_tot
    em_rates_d = em_rate_tot - em_rates_a
    return em_rates_d, em_rates_a


Instruction:
Given the following Python 3 function, write the documentation
def em_rates_from_E_unique(em_rate_tot, E_values):
    em_rates_d, em_rates_a = em_rates_from_E_DA(em_rate_tot, E_values)
    return np.unique(np.hstack([em_rates_d, em_rates_a]))

Response: Array of unique emission rates for given total emission and E.


Instruction:
Can you generate the documentation for the following Python 3 function
def em_rates_from_E_DA_mix(em_rates_tot, E_values):
    em_rates_d, em_rates_a = [], []
    for em_rate_tot, E_value in zip(em_rates_tot, E_values):
        em_rate_di, em_rate_ai = em_rates_from_E_DA(em_rate_tot, E_value)
        em_rates_d.append(em_rate_di)
        em_rates_a.append(em_rate_ai)
    return em_rates_d, em_rates_a

Response: Returns D and A emission rates for two populations.


Instruction:
How would you explain what the following Python 3 function does
def populations_diff_coeff(particles, populations):
    D_counts = particles.diffusion_coeff_counts
    if len(D_counts) == 1:
        pop_sizes = [pop.stop - pop.start for pop in populations]
        assert D_counts[0][1] >= sum(pop_sizes)
        D_counts = [(D_counts[0][0], ps) for ps in pop_sizes]

    D_list = []
    D_pop_start = 0  # start index of diffusion-based populations
    for pop, (D, counts) in zip(populations, D_counts):
        D_list.append(D)
        assert pop.start >= D_pop_start
        assert pop.stop <= D_pop_start + counts
        D_pop_start += counts
    return D_list

Response: Return the diffusion coefficients of the two specified populations.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def populations_slices(particles, num_pop_list):
    slices = []
    i_prev = 0
    for num_pop in num_pop_list:
        slices.append(slice(i_prev, i_prev + num_pop))
        i_prev += num_pop
    return slices

Response: 2 - tuple of slices for selection of two populations.


Instruction:
Can you generate the documentation for the following Python 3 function
def _calc_hash_da(self, rs):
        self.hash_d = hash_(rs.get_state())[:6]
        self.hash_a = self.hash_d

Response: Compute hash of D and A timestamps for single - step D + A case.


Instruction:
Create a Python 3 function for
computing timestamps for current populations.

Response:
def run(self, rs, overwrite=True, skip_existing=False, path=None,
            chunksize=None):
        """Compute timestamps for current populations."""
        if path is None:
            path = str(self.S.store.filepath.parent)
        kwargs = dict(rs=rs, overwrite=overwrite, path=path,
                      timeslice=self.timeslice, skip_existing=skip_existing)
        if chunksize is not None:
            kwargs['chunksize'] = chunksize
        header = ' - Mixture Simulation:'

        # Donor timestamps hash is from the input RandomState
        self.hash_d = hash_(rs.get_state())[:6]   # needed by merge_da()
        print('%s Donor timestamps -    %s' % (header, ctime()), flush=True)
        self.S.simulate_timestamps_mix(
            populations = self.populations,
            max_rates = self.em_rates_d,
            bg_rate = self.bg_rate_d,
            **kwargs)

        # Acceptor timestamps hash is from 'last_random_state' attribute
        # of the donor timestamps. This allows deterministic generation of
        # donor + acceptor timestamps given the input random state.
        ts_d, _ = self.S.get_timestamps_part(self.name_timestamps_d)
        rs.set_state(ts_d.attrs['last_random_state'])
        self.hash_a = hash_(rs.get_state())[:6]   # needed by merge_da()
        print('\n%s Acceptor timestamps - %s' % (header, ctime()), flush=True)
        self.S.simulate_timestamps_mix(
            populations = self.populations,
            max_rates = self.em_rates_a,
            bg_rate = self.bg_rate_a,
            **kwargs)
        print('\n%s Completed. %s' % (header, ctime()), flush=True)


Instruction:
Write a Python 3 function that can
compute timestamps for current populations.

Response:
def run_da(self, rs, overwrite=True, skip_existing=False, path=None,
               chunksize=None):
        """Compute timestamps for current populations."""
        if path is None:
            path = str(self.S.store.filepath.parent)
        kwargs = dict(rs=rs, overwrite=overwrite, path=path,
                      timeslice=self.timeslice, skip_existing=skip_existing)
        if chunksize is not None:
            kwargs['chunksize'] = chunksize
        header = ' - Mixture Simulation:'

        # Donor timestamps hash is from the input RandomState
        self._calc_hash_da(rs)
        print('%s Donor + Acceptor timestamps - %s' %
              (header, ctime()), flush=True)
        self.S.simulate_timestamps_mix_da(
            max_rates_d = self.em_rates_d,
            max_rates_a = self.em_rates_a,
            populations = self.populations,
            bg_rate_d = self.bg_rate_d,
            bg_rate_a = self.bg_rate_a,
            **kwargs)
        print('\n%s Completed. %s' % (header, ctime()), flush=True)


Instruction:
Write a Python 3 function for
merging donor and acceptor timestamps computes ts a_ch part.

Response:
def merge_da(self):
        """Merge donor and acceptor timestamps, computes `ts`, `a_ch`, `part`.
        """
        print(' - Merging D and A timestamps', flush=True)
        ts_d, ts_par_d = self.S.get_timestamps_part(self.name_timestamps_d)
        ts_a, ts_par_a = self.S.get_timestamps_part(self.name_timestamps_a)
        ts, a_ch, part = merge_da(ts_d, ts_par_d, ts_a, ts_par_a)
        assert a_ch.sum() == ts_a.shape[0]
        assert (~a_ch).sum() == ts_d.shape[0]
        assert a_ch.size == ts_a.shape[0] + ts_d.shape[0]
        self.ts, self.a_ch, self.part = ts, a_ch, part
        self.clk_p = ts_d.attrs['clk_p']


Instruction:
Can you generate a brief explanation for the following Python 3 code
def save_photon_hdf5(self, identity=None, overwrite=True, path=None):
        filepath = self.filepath
        if path is not None:
            filepath = Path(path, filepath.name)
        self.merge_da()
        data = self._make_photon_hdf5(identity=identity)
        phc.hdf5.save_photon_hdf5(data, h5_fname=str(filepath),
                                  overwrite=overwrite)

Response: Create a smFRET Photon - HDF5 file with current timestamps.


Instruction:
Write a Python 3 script for
printing the HDF5 attributes for node_name.

Response:
def print_attrs(data_file, node_name='/', which='user', compress=False):
    """Print the HDF5 attributes for `node_name`.

    Parameters:
        data_file (pytables HDF5 file object): the data file to print
        node_name (string): name of the path inside the file to be printed.
            Can be either a group or a leaf-node. Default: '/', the root node.
        which (string): Valid values are 'user' for user-defined attributes,
            'sys' for pytables-specific attributes and 'all' to print both
            groups of attributes. Default 'user'.
        compress (bool): if True displays at most a line for each attribute.
            Default False.
    """
    node = data_file.get_node(node_name)
    print ('List of attributes for:\n  %s\n' % node)
    for attr in node._v_attrs._f_list():
        print ('\t%s' % attr)
        attr_content = repr(node._v_attrs[attr])
        if compress:
            attr_content = attr_content.split('\n')[0]
        print ("\t    %s" % attr_content)


Instruction:
Write a Python 3 function for
printing all the sub - groups in group and leaf - nodes children of group.

Response:
def print_children(data_file, group='/'):
    """Print all the sub-groups in `group` and leaf-nodes children of `group`.

    Parameters:
        data_file (pytables HDF5 file object): the data file to print
        group (string): path name of the group to be printed.
            Default: '/', the root node.
    """
    base = data_file.get_node(group)
    print ('Groups in:\n  %s\n' % base)

    for node in base._f_walk_groups():
        if node is not base:
            print ('    %s' % node)

    print ('\nLeaf-nodes in %s:' % group)
    for node in base._v_leaves.itervalues():
        info = node.shape
        if len(info) == 0:
            info = node.read()
        print ('\t%s, %s' % (node.name, info))
        if len(node.title) > 0:
            print ('\t    %s' % node.title)


Instruction:
Implement a function in Python 3 to
train model on given training examples and return the list of costs after each minibatch is processed.

Response:
def fit(self, trX, trY, batch_size=64, n_epochs=1, len_filter=LenFilter(), snapshot_freq=1, path=None):
        """Train model on given training examples and return the list of costs after each minibatch is processed.

        Args:
          trX (list) -- Inputs
          trY (list) -- Outputs
          batch_size (int, optional) -- number of examples in a minibatch (default 64)
          n_epochs (int, optional)  -- number of epochs to train for (default 1)
          len_filter (object, optional) -- object to filter training example by length (default LenFilter())
          snapshot_freq (int, optional) -- number of epochs between saving model snapshots (default 1)
          path (str, optional) -- prefix of path where model snapshots are saved.
            If None, no snapshots are saved (default None)

        Returns:
          list -- costs of model after processing each minibatch
        """
        if len_filter is not None:
            trX, trY = len_filter.filter(trX, trY)
        trY = standardize_targets(trY, cost=self.cost)

        n = 0.
        t = time()
        costs = []
        for e in range(n_epochs):
            epoch_costs = []
            for xmb, ymb in self.iterator.iterXY(trX, trY):
                c = self._train(xmb, ymb)
                epoch_costs.append(c)
                n += len(ymb)
                if self.verbose >= 2:
                    n_per_sec = n / (time() - t)
                    n_left = len(trY) - n % len(trY)
                    time_left = n_left/n_per_sec
                    sys.stdout.write("\rEpoch %d Seen %d samples Avg cost %0.4f Time left %d seconds" % (e, n, np.mean(epoch_costs[-250:]), time_left))
                    sys.stdout.flush()
            costs.extend(epoch_costs)

            status = "Epoch %d Seen %d samples Avg cost %0.4f Time elapsed %d seconds" % (e, n, np.mean(epoch_costs[-250:]), time() - t)
            if self.verbose >= 2:
                sys.stdout.write("\r"+status)
                sys.stdout.flush()
                sys.stdout.write("\n")
            elif self.verbose == 1:
                print(status)
            if path and e % snapshot_freq == 0:
                save(self, "{0}.{1}".format(path, e))
        return costs


Instruction:
Create a Python 3 function for
generating a VAO that is a plane on the xz axis of a specific size and resolution.

Response:
def plane_xz(size=(10, 10), resolution=(10, 10)) -> VAO:
    """
    Generates a plane on the xz axis of a specific size and resolution.
    Normals and texture coordinates are also included.

    Args:
        size: (x, y) tuple
        resolution: (x, y) tuple

    Returns:
        A :py:class:`demosys.opengl.vao.VAO` instance
    """
    sx, sz = size
    rx, rz = resolution
    dx, dz = sx / rx, sz / rz  # step
    ox, oz = -sx / 2, -sz / 2  # start offset

    def gen_pos():
        for z in range(rz):
            for x in range(rx):
                yield ox + x * dx
                yield 0
                yield oz + z * dz

    def gen_uv():
        for z in range(rz):
            for x in range(rx):
                yield x / (rx - 1)
                yield 1 - z / (rz - 1)

    def gen_normal():
        for _ in range(rx * rz):
            yield 0.0
            yield 1.0
            yield 0.0

    def gen_index():
        for z in range(rz - 1):
            for x in range(rx - 1):
                # quad poly left
                yield z * rz + x + 1
                yield z * rz + x
                yield z * rz + x + rx
                # quad poly right
                yield z * rz + x + 1
                yield z * rz + x + rx
                yield z * rz + x + rx + 1

    pos_data = numpy.fromiter(gen_pos(), dtype=numpy.float32)
    uv_data = numpy.fromiter(gen_uv(), dtype=numpy.float32)
    normal_data = numpy.fromiter(gen_normal(), dtype=numpy.float32)
    index_data = numpy.fromiter(gen_index(), dtype=numpy.uint32)

    vao = VAO("plane_xz", mode=moderngl.TRIANGLES)

    vao.buffer(pos_data, '3f', ['in_position'])
    vao.buffer(uv_data, '2f', ['in_uv'])
    vao.buffer(normal_data, '3f', ['in_normal'])

    vao.index_buffer(index_data, index_element_size=4)

    return vao


Instruction:
Can you generate a brief explanation for the following Python 3 code
def load(self):
        self.path = self.find_scene(self.meta.path)
        if not self.path:
            raise ValueError("Scene '{}' not found".format(self.meta.path))

        self.scene = Scene(self.path)

        # Load gltf json file
        if self.path.suffix == '.gltf':
            self.load_gltf()

        # Load binary gltf file
        if self.path.suffix == '.glb':
            self.load_glb()

        self.meta.check_version()
        self.meta.check_extensions(self.supported_extensions)
        self.load_images()
        self.load_samplers()
        self.load_textures()
        self.load_materials()
        self.load_meshes()
        self.load_nodes()

        self.scene.calc_scene_bbox()
        self.scene.prepare()

        return self.scene

Response: Load the object containing the current metadata and return it.


Instruction:
How would you code a function in Python 3 to
load a gltf json file

Response:
def load_gltf(self):
        """Loads a gltf json file"""
        with open(self.path) as fd:
            self.meta = GLTFMeta(self.path, json.load(fd))


Instruction:
Can you generate a brief explanation for the following Python 3 code
def load_glb(self):
        with open(self.path, 'rb') as fd:
            # Check header
            magic = fd.read(4)
            if magic != GLTF_MAGIC_HEADER:
                raise ValueError("{} has incorrect header {} != {}".format(self.path, magic, GLTF_MAGIC_HEADER))

            version = struct.unpack('<I', fd.read(4))[0]
            if version != 2:
                raise ValueError("{} has unsupported version {}".format(self.path, version))

            # Total file size including headers
            _ = struct.unpack('<I', fd.read(4))[0]  # noqa

            # Chunk 0 - json
            chunk_0_length = struct.unpack('<I', fd.read(4))[0]
            chunk_0_type = fd.read(4)
            if chunk_0_type != b'JSON':
                raise ValueError("Expected JSON chunk, not {} in file {}".format(chunk_0_type, self.path))

            json_meta = fd.read(chunk_0_length).decode()

            # chunk 1 - binary buffer
            chunk_1_length = struct.unpack('<I', fd.read(4))[0]
            chunk_1_type = fd.read(4)
            if chunk_1_type != b'BIN\x00':
                raise ValueError("Expected BIN chunk, not {} in file {}".format(chunk_1_type, self.path))

            self.meta = GLTFMeta(self.path, json.loads(json_meta), binary_buffer=fd.read(chunk_1_length))

Response: Loads a binary gltf file


Instruction:
Can you write a function in Python 3 where it
links data to the internal data structures.

Response:
def _link_data(self):
        """Add references"""
        # accessors -> buffer_views -> buffers
        for acc in self.accessors:
            acc.bufferView = self.buffer_views[acc.bufferViewId]

        for buffer_view in self.buffer_views:
            buffer_view.buffer = self.buffers[buffer_view.bufferId]

        # Link accessors to mesh primitives
        for mesh in self.meshes:
            for primitive in mesh.primitives:
                if getattr(primitive, "indices", None) is not None:
                    primitive.indices = self.accessors[primitive.indices]
                for name, value in primitive.attributes.items():
                    primitive.attributes[name] = self.accessors[value]

        # Link buffer views to images
        for image in self.images:
            if image.bufferViewId is not None:
                image.bufferView = self.buffer_views[image.bufferViewId]