Instruction:
Can you generate a brief explanation for the following Python 3 code
def pfd(X, D=None):
    if D is None:
        D = numpy.diff(X)
        D = D.tolist()
    N_delta = 0  # number of sign changes in derivative of the signal
    for i in range(1, len(D)):
        if D[i] * D[i - 1] < 0:
            N_delta += 1
    n = len(X)
    return numpy.log10(n) / (
        numpy.log10(n) + numpy.log10(n / n + 0.4 * N_delta)
    )

Response: Compute Petrosian Fractal Dimension of a time series X.


Instruction:
Implement a Python 3 function for
computing Hjorth Fractal Dimension of a time series X and kmax is an HFD parameter

Response:
def hfd(X, Kmax):
    """ Compute Hjorth Fractal Dimension of a time series X, kmax
     is an HFD parameter
    """
    L = []
    x = []
    N = len(X)
    for k in range(1, Kmax):
        Lk = []
        for m in range(0, k):
            Lmk = 0
            for i in range(1, int(numpy.floor((N - m) / k))):
                Lmk += abs(X[m + i * k] - X[m + i * k - k])
            Lmk = Lmk * (N - 1) / numpy.floor((N - m) / float(k)) / k
            Lk.append(Lmk)
        L.append(numpy.log(numpy.mean(Lk)))
        x.append([numpy.log(float(1) / k), 1])

    (p, r1, r2, s) = numpy.linalg.lstsq(x, L)
    return p[0]


Instruction:
Explain what the following Python 3 code does
def hjorth(X, D=None):

    if D is None:
        D = numpy.diff(X)
        D = D.tolist()

    D.insert(0, X[0])  # pad the first difference
    D = numpy.array(D)

    n = len(X)

    M2 = float(sum(D ** 2)) / n
    TP = sum(numpy.array(X) ** 2)
    M4 = 0
    for i in range(1, len(D)):
        M4 += (D[i] - D[i - 1]) ** 2
    M4 = M4 / n

    return numpy.sqrt(M2 / TP), numpy.sqrt(
        float(M4) * TP / M2 / M2
    )

Response: Compute Hjorth mobility and complexity of a time series X and D.


Instruction:
Implement a function in Python 3 to
compute the spectral entropy of a time series X in a frequency domain band and frequency spectrum Fs.

Response:
def spectral_entropy(X, Band, Fs, Power_Ratio=None):
    """Compute spectral entropy of a time series from either two cases below:
    1. X, the time series (default)
    2. Power_Ratio, a list of normalized signal power in a set of frequency
    bins defined in Band (if Power_Ratio is provided, recommended to speed up)

    In case 1, Power_Ratio is computed by bin_power() function.

    Notes
    -----
    To speed up, it is recommended to compute Power_Ratio before calling this
    function because it may also be used by other functions whereas computing
    it here again will slow down.

    Parameters
    ----------

    Band
        list

        boundary frequencies (in Hz) of bins. They can be unequal bins, e.g.
        [0.5,4,7,12,30] which are delta, theta, alpha and beta respectively.
        You can also use range() function of Python to generate equal bins and
        pass the generated list to this function.

        Each element of Band is a physical frequency and shall not exceed the
        Nyquist frequency, i.e., half of sampling frequency.

     X
        list

        a 1-D real time series.

    Fs
        integer

        the sampling rate in physical frequency

    Returns
    -------

    As indicated in return line

    See Also
    --------
    bin_power: pyeeg function that computes spectral power in frequency bins

    """

    if Power_Ratio is None:
        Power, Power_Ratio = bin_power(X, Band, Fs)

    Spectral_Entropy = 0
    for i in range(0, len(Power_Ratio) - 1):
        Spectral_Entropy += Power_Ratio[i] * numpy.log(Power_Ratio[i])
    Spectral_Entropy /= numpy.log(
        len(Power_Ratio)
    )  # to save time, minus one is omitted
    return -1 * Spectral_Entropy


Instruction:
Given the following Python 3 function, write the documentation
def svd_entropy(X, Tau, DE, W=None):

    if W is None:
        Y = embed_seq(X, Tau, DE)
        W = numpy.linalg.svd(Y, compute_uv=0)
        W /= sum(W)  # normalize singular values

    return -1 * sum(W * numpy.log(W))

Response: Compute SVD Entropy from two cases below.


Instruction:
Explain what the following Python 3 code does
def ap_entropy(X, M, R):
    N = len(X)

    Em = embed_seq(X, 1, M)
    A = numpy.tile(Em, (len(Em), 1, 1))
    B = numpy.transpose(A, [1, 0, 2])
    D = numpy.abs(A - B) #  D[i,j,k] = |Em[i][k] - Em[j][k]|
    InRange = numpy.max(D, axis=2) <= R
    Cm = InRange.mean(axis=0) #  Probability that random M-sequences are in range

    # M+1-sequences in range iff M-sequences are in range & last values are close
    Dp = numpy.abs(numpy.tile(X[M:], (N - M, 1)) - numpy.tile(X[M:], (N - M, 1)).T)
    Cmp = numpy.logical_and(Dp <= R, InRange[:-1, :-1]).mean(axis=0)

    # Uncomment for old (miscounted) version
    #Cm += 1 / (N - M +1); Cm[-1] -= 1 / (N - M + 1)
    #Cmp += 1 / (N - M)

    Phi_m, Phi_mp = numpy.sum(numpy.log(Cm)), numpy.sum(numpy.log(Cmp))

    Ap_En = (Phi_m - Phi_mp) / (N - M)

    return Ap_En

Response: Computeer approximate entropy of series X specified by M and R.


Instruction:
Can you implement a function in Python 3 that
computes Detrended Fluctuation Analysis from a time series X and length of boxes L.

Response:
def dfa(X, Ave=None, L=None):
    """Compute Detrended Fluctuation Analysis from a time series X and length of
    boxes L.

    The first step to compute DFA is to integrate the signal. Let original
    series be X= [x(1), x(2), ..., x(N)].

    The integrated signal Y = [y(1), y(2), ..., y(N)] is obtained as follows
    y(k) = \sum_{i=1}^{k}{x(i)-Ave} where Ave is the mean of X.

    The second step is to partition/slice/segment the integrated sequence Y
    into boxes. At least two boxes are needed for computing DFA. Box sizes are
    specified by the L argument of this function. By default, it is from 1/5 of
    signal length to one (x-5)-th of the signal length, where x is the nearest
    power of 2 from the length of the signal, i.e., 1/16, 1/32, 1/64, 1/128,
    ...

    In each box, a linear least square fitting is employed on data in the box.
    Denote the series on fitted line as Yn. Its k-th elements, yn(k),
    corresponds to y(k).

    For fitting in each box, there is a residue, the sum of squares of all
    offsets, difference between actual points and points on fitted line.

    F(n) denotes the square root of average total residue in all boxes when box
    length is n, thus
    Total_Residue = \sum_{k=1}^{N}{(y(k)-yn(k))}
    F(n) = \sqrt(Total_Residue/N)

    The computing to F(n) is carried out for every box length n. Therefore, a
    relationship between n and F(n) can be obtained. In general, F(n) increases
    when n increases.

    Finally, the relationship between F(n) and n is analyzed. A least square
    fitting is performed between log(F(n)) and log(n). The slope of the fitting
    line is the DFA value, denoted as Alpha. To white noise, Alpha should be
    0.5. Higher level of signal complexity is related to higher Alpha.

    Parameters
    ----------

    X:
        1-D Python list or numpy array
        a time series

    Ave:
        integer, optional
        The average value of the time series

    L:
        1-D Python list of integers
        A list of box size, integers in ascending order

    Returns
    -------

    Alpha:
        integer
        the result of DFA analysis, thus the slope of fitting line of log(F(n))
        vs. log(n). where n is the

    Examples
    --------
    >>> import pyeeg
    >>> from numpy.random import randn
    >>> print(pyeeg.dfa(randn(4096)))
    0.490035110345

    Reference
    ---------
    Peng C-K, Havlin S, Stanley HE, Goldberger AL. Quantification of scaling
    exponents and crossover phenomena in nonstationary heartbeat time series.
    _Chaos_ 1995;5:82-87

    Notes
    -----

    This value depends on the box sizes very much. When the input is a white
    noise, this value should be 0.5. But, some choices on box sizes can lead to
    the value lower or higher than 0.5, e.g. 0.38 or 0.58.

    Based on many test, I set the box sizes from 1/5 of    signal length to one
    (x-5)-th of the signal length, where x is the nearest power of 2 from the
    length of the signal, i.e., 1/16, 1/32, 1/64, 1/128, ...

    You may generate a list of box sizes and pass in such a list as a
    parameter.

    """

    X = numpy.array(X)

    if Ave is None:
        Ave = numpy.mean(X)

    Y = numpy.cumsum(X)
    Y -= Ave

    if L is None:
        L = numpy.floor(len(X) * 1 / (
            2 ** numpy.array(list(range(4, int(numpy.log2(len(X))) - 4))))
        )

    F = numpy.zeros(len(L))  # F(n) of different given box length n

    for i in range(0, len(L)):
        n = int(L[i])                        # for each box length L[i]
        if n == 0:
            print("time series is too short while the box length is too big")
            print("abort")
            exit()
        for j in range(0, len(X), n):  # for each box
            if j + n < len(X):
                c = list(range(j, j + n))
                # coordinates of time in the box
                c = numpy.vstack([c, numpy.ones(n)]).T
                # the value of data in the box
                y = Y[j:j + n]
                # add residue in this box
                F[i] += numpy.linalg.lstsq(c, y)[1]
        F[i] /= ((len(X) / n) * n)
    F = numpy.sqrt(F)

    Alpha = numpy.linalg.lstsq(numpy.vstack(
        [numpy.log(L), numpy.ones(len(L))]
    ).T, numpy.log(F))[0][0]

    return Alpha


Instruction:
Given the following Python 3 function, write the documentation
def permutation_entropy(x, n, tau):

    PeSeq = []
    Em = embed_seq(x, tau, n)

    for i in range(0, len(Em)):
        r = []
        z = []

        for j in range(0, len(Em[i])):
            z.append(Em[i][j])

        for j in range(0, len(Em[i])):
            z.sort()
            r.append(z.index(Em[i][j]))
            z[z.index(Em[i][j])] = -1

        PeSeq.append(r)

    RankMat = []

    while len(PeSeq) > 0:
        RankMat.append(PeSeq.count(PeSeq[0]))
        x = PeSeq[0]
        for j in range(0, PeSeq.count(PeSeq[0])):
            PeSeq.pop(PeSeq.index(x))

    RankMat = numpy.array(RankMat)
    RankMat = numpy.true_divide(RankMat, RankMat.sum())
    EntropyMat = numpy.multiply(numpy.log2(RankMat), RankMat)
    PE = -1 * EntropyMat.sum()

    return PE

Response: Compute the Permutation Entropy of a given time series x.


Instruction:
Here you have a function in Python 3, explain what it does
def information_based_similarity(x, y, n):

    Wordlist = []
    Space = [[0, 0], [0, 1], [1, 0], [1, 1]]
    Sample = [0, 1]

    if (n == 1):
        Wordlist = Sample

    if (n == 2):
        Wordlist = Space

    elif (n > 1):
        Wordlist = Space
        Buff = []
        for k in range(0, n - 2):
            Buff = []

            for i in range(0, len(Wordlist)):
                Buff.append(tuple(Wordlist[i]))
            Buff = tuple(Buff)

            Wordlist = []
            for i in range(0, len(Buff)):
                for j in range(0, len(Sample)):
                    Wordlist.append(list(Buff[i]))
                    Wordlist[len(Wordlist) - 1].append(Sample[j])

    Wordlist.sort()

    Input = [[], []]
    Input[0] = x
    Input[1] = y

    SymbolicSeq = [[], []]
    for i in range(0, 2):
        Encoder = numpy.diff(Input[i])
        for j in range(0, len(Input[i]) - 1):
            if(Encoder[j] > 0):
                SymbolicSeq[i].append(1)
            else:
                SymbolicSeq[i].append(0)

    Wm = []
    Wm.append(embed_seq(SymbolicSeq[0], 1, n).tolist())
    Wm.append(embed_seq(SymbolicSeq[1], 1, n).tolist())

    Count = [[], []]
    for i in range(0, 2):
        for k in range(0, len(Wordlist)):
            Count[i].append(Wm[i].count(Wordlist[k]))

    Prob = [[], []]
    for i in range(0, 2):
        Sigma = 0
        for j in range(0, len(Wordlist)):
            Sigma += Count[i][j]
        for k in range(0, len(Wordlist)):
            Prob[i].append(numpy.true_divide(Count[i][k], Sigma))

    Entropy = [[], []]
    for i in range(0, 2):
        for k in range(0, len(Wordlist)):
            if (Prob[i][k] == 0):
                Entropy[i].append(0)
            else:
                Entropy[i].append(Prob[i][k] * (numpy.log2(Prob[i][k])))

    Rank = [[], []]
    Buff = [[], []]
    Buff[0] = tuple(Count[0])
    Buff[1] = tuple(Count[1])
    for i in range(0, 2):
        Count[i].sort()
        Count[i].reverse()
        for k in range(0, len(Wordlist)):
            Rank[i].append(Count[i].index(Buff[i][k]))
            Count[i][Count[i].index(Buff[i][k])] = -1

    IBS = 0
    Z = 0
    n = 0
    for k in range(0, len(Wordlist)):
        if ((Buff[0][k] != 0) & (Buff[1][k] != 0)):
            F = -Entropy[0][k] - Entropy[1][k]
            IBS += numpy.multiply(numpy.absolute(Rank[0][k] - Rank[1][k]), F)
            Z += F
        else:
            n += 1

    IBS = numpy.true_divide(IBS, Z)
    IBS = numpy.true_divide(IBS, len(Wordlist) - n)

    return IBS

Response: Calculates the information based similarity between two time series x and y.


Instruction:
Write a Python 3 function for
calculating the largest Lyauponov exponent of a given time series x using the Losenstein algorithm.

Response:
def LLE(x, tau, n, T, fs):
    """Calculate largest Lyauponov exponent of a given time series x using
    Rosenstein algorithm.

    Parameters
    ----------

    x
        list

        a time series

    n
        integer

        embedding dimension

    tau
        integer

        Embedding lag

    fs
        integer

        Sampling frequency

    T
        integer

        Mean period

    Returns
    ----------

    Lexp
       float

       Largest Lyapunov Exponent

    Notes
    ----------
    A n-dimensional trajectory is first reconstructed from the observed data by
    use of embedding delay of tau, using pyeeg function, embed_seq(x, tau, n).
    Algorithm then searches for nearest neighbour of each point on the
    reconstructed trajectory; temporal separation of nearest neighbours must be
    greater than mean period of the time series: the mean period can be
    estimated as the reciprocal of the mean frequency in power spectrum

    Each pair of nearest neighbours is assumed to diverge exponentially at a
    rate given by largest Lyapunov exponent. Now having a collection of
    neighbours, a least square fit to the average exponential divergence is
    calculated. The slope of this line gives an accurate estimate of the
    largest Lyapunov exponent.

    References
    ----------
    Rosenstein, Michael T., James J. Collins, and Carlo J. De Luca. "A
    practical method for calculating largest Lyapunov exponents from small data
    sets." Physica D: Nonlinear Phenomena 65.1 (1993): 117-134.

    Examples
    ----------
    >>> import pyeeg
    >>> X = numpy.array([3,4,1,2,4,51,4,32,24,12,3,45])
    >>> pyeeg.LLE(X,2,4,1,1)
    >>> 0.18771136179353307

    """

    Em = embed_seq(x, tau, n)
    M = len(Em)
    A = numpy.tile(Em, (len(Em), 1, 1))
    B = numpy.transpose(A, [1, 0, 2])
    square_dists = (A - B) ** 2 #  square_dists[i,j,k] = (Em[i][k]-Em[j][k])^2
    D = numpy.sqrt(square_dists[:,:,:].sum(axis=2)) #  D[i,j] = ||Em[i]-Em[j]||_2

    # Exclude elements within T of the diagonal
    band = numpy.tri(D.shape[0], k=T) - numpy.tri(D.shape[0], k=-T-1)
    band[band == 1] = numpy.inf
    neighbors = (D + band).argmin(axis=0) #  nearest neighbors more than T steps away

    # in_bounds[i,j] = (i+j <= M-1 and i+neighbors[j] <= M-1)
    inc = numpy.tile(numpy.arange(M), (M, 1))
    row_inds = (numpy.tile(numpy.arange(M), (M, 1)).T + inc)
    col_inds = (numpy.tile(neighbors, (M, 1)) + inc.T)
    in_bounds = numpy.logical_and(row_inds <= M - 1, col_inds <= M - 1)
    # Uncomment for old (miscounted) version
    #in_bounds = numpy.logical_and(row_inds < M - 1, col_inds < M - 1)
    row_inds[-in_bounds] = 0
    col_inds[-in_bounds] = 0

    # neighbor_dists[i,j] = ||Em[i+j]-Em[i+neighbors[j]]||_2
    neighbor_dists = numpy.ma.MaskedArray(D[row_inds, col_inds], -in_bounds)
    J = (-neighbor_dists.mask).sum(axis=1) #  number of in-bounds indices by row
    # Set invalid (zero) values to 1; log(1) = 0 so sum is unchanged
    neighbor_dists[neighbor_dists == 0] = 1
    d_ij = numpy.sum(numpy.log(neighbor_dists.data), axis=1)
    mean_d = d_ij[J > 0] / J[J > 0]

    x = numpy.arange(len(mean_d))
    X = numpy.vstack((x, numpy.ones(len(mean_d)))).T
    [m, c] = numpy.linalg.lstsq(X, mean_d)[0]
    Lexp = fs * m
    return Lexp


Instruction:
Implement a Python 3 function for
returning a list of time series representing the period of each successive oscillation in the given time series.

Response:
def periods(ts, phi=0.0):
    """For a single variable timeseries representing the phase of an oscillator,
    measure the period of each successive oscillation.

    An individual oscillation is defined to start and end when the phase
    passes phi (by default zero) after completing a full cycle.

    If the timeseries begins (or ends) exactly at phi, then the first
    (or last) oscillation will be included.

    Arguments:
      ts: Timeseries (single variable)
          The timeseries of an angle variable (radians)

      phi (float): A single oscillation starts and ends at phase phi (by
        default zero).
    """
    ts = np.squeeze(ts)
    if ts.ndim <= 1:
        return np.diff(phase_crossings(ts, phi))
    else:
        return np.hstack([ts[...,i].periods(phi) for i in range(ts.shape[-1])])


Instruction:
Explain what the following Python 3 code does
def order_param(ts, axis=2):
    return np.abs(np.exp(1.0j * ts).mean(axis=axis))

Response: Order parameter of phase synchronization


Instruction:
Explain what the following Python 3 code does
def cwtmorlet(points, width):
    omega = 5.0
    s = points / (2.0 * omega * width)
    return wavelets.morlet(points, omega, s, complete=True)

Response: Complex morlet wavelet function compatible with scipy. signal. cwt


Instruction:
Explain what the following Python 3 code does
def roughcwt(data, wavelet, widths):
    out_dtype = wavelet(widths[0], widths[0]).dtype
    output = np.zeros([len(widths), len(data)], dtype=out_dtype)
    for ind, width in enumerate(widths):
        wavelet_data = wavelet(min(3 * width, len(data)), width)
        output[ind, :] = convolve(data, wavelet_data,
                                              mode='same')
    return output

Response: A CWT implementation that uses a continuous wavelet transform on data.


Instruction:
Can you tell what is the following Python 3 function doing
def _rescale(ar):
    max = np.nanmax(ar)
    min = np.nanmin(ar)
    midpoint = (max + min) / 2.0
    return 2.0 * (ar - midpoint) / (max - min)

Response: Shift and rescale array ar to the interval - 1 1


Instruction:
How would you explain what the following Python 3 function does
def _get_color_list():
    if 'axes.prop_cycle' in plt.rcParams:
        return [p['color'] for p in list(plt.rcParams['axes.prop_cycle'])]
    else:
        return plt.rcParams['axes.color_cycle']

Response: Get cycle of colors in a way compatible with all matplotlib versions


Instruction:
Write a Python 3 script to
plot the timeseries and variability. Optionally plot epochs.

Response:
def _plot_variability(ts, variability, threshold=None, epochs=None):
    """Plot the timeseries and variability. Optionally plot epochs."""
    import matplotlib.style
    import matplotlib as mpl
    mpl.style.use('classic')
    import matplotlib.pyplot as plt
    if variability.ndim is 1:
        variability = variability[:, np.newaxis, np.newaxis]
    elif variability.ndim is 2:
        variability = variability[:, np.newaxis, :]
    vmeasures = variability.shape[2]
    channels = ts.shape[1]
    dt = (1.0*ts.tspan[-1] - ts.tspan[0]) / (len(ts) - 1)
    fig = plt.figure()
    ylabelprops = dict(rotation=0,
                       horizontalalignment='right',
                       verticalalignment='center',
                       x=-0.01)
    for i in range(channels):
        rect = (0.1, 0.85*(channels - i - 1)/channels + 0.1,
                0.8, 0.85/channels)
        axprops = dict()
        if channels > 10:
            axprops['yticks'] = []
        ax = fig.add_axes(rect, **axprops)
        ax.plot(ts.tspan, ts[:, i])
        if ts.labels[1] is None:
            ax.set_ylabel(u'channel %d' % i, **ylabelprops)
        else:
            ax.set_ylabel(ts.labels[1][i], **ylabelprops)
        plt.setp(ax.get_xticklabels(), visible=False)
        if i is channels - 1:
            plt.setp(ax.get_xticklabels(), visible=True)
            ax.set_xlabel('time (s)')
        ax2 = ax.twinx()
        if vmeasures > 1:
            mean_v = np.nanmean(variability[:, i, :], axis=1)
            ax2.plot(ts.tspan, mean_v, color='g')
            colors = _get_color_list()
            for j in range(vmeasures):
                ax2.plot(ts.tspan, variability[:, i, j], linestyle='dotted',
                         color=colors[(3 + j) % len(colors)])
            if i is 0:
                ax2.legend(['variability (mean)'] +
                          ['variability %d' % j for j in range(vmeasures)],
                          loc='best')
        else:
            ax2.plot(ts.tspan, variability[:, i, 0])
            ax2.legend(('variability',), loc='best')
        if threshold is not None:
            ax2.axhline(y=threshold, color='Gray', linestyle='dashed')
        ax2.set_ylabel('variability')
        ymin = np.nanmin(ts[:, i])
        ymax = np.nanmax(ts[:, i])
        tstart = ts.tspan[0]
        if epochs:
            # highlight epochs using rectangular patches
            for e in epochs[i]:
                t1 = tstart + (e[0] - 1) * dt
                ax.add_patch(mpl.patches.Rectangle(
                    (t1, ymin), (e[1] - e[0])*dt, ymax - ymin, alpha=0.2,
                    color='green', ec='none'))
    fig.axes[0].set_title(u'variability (threshold = %g)' % threshold)
    fig.show()


Instruction:
Explain what the following Python 3 code does
def epochs(ts, variability=None, threshold=0.0, minlength=1.0, plot=True):
    if variability is None:
        variability = ts.variability_fp(plot=False)
    orig_ndim = ts.ndim
    if ts.ndim is 1:
        ts = ts[:, np.newaxis]
    if variability.ndim is 1:
        variability = variability[:, np.newaxis, np.newaxis]
    elif variability.ndim is 2:
        variability = variability[:, np.newaxis, :]
    channels = ts.shape[1]
    n = len(ts)
    dt = (1.0*ts.tspan[-1] - ts.tspan[0]) / (n - 1)
    fs = 1.0 / dt
    allchannels_epochs = []
    for i in range(channels):
        v = variability[:, i, :]
        v = np.nanmean(v, axis=1) # mean of q different variability measures
        # then smooth the variability with a low-pass filter
        nonnan_ix = np.nonzero(~np.isnan(v))[0]
        nonnans = slice(nonnan_ix.min(), nonnan_ix.max())
        crit_freq = 1.0 # Hz
        b, a = signal.butter(3, 2.0 * crit_freq / fs)
        #v[nonnans] = signal.filtfilt(b, a, v[nonnans])
        v[nonnan_ix] = signal.filtfilt(b, a, v[nonnan_ix])
        # find all local minima of the variability not exceeding the threshold
        m = v[1:-1]
        l = v[0:-2]
        r = v[2:]
        minima = np.nonzero(~np.isnan(m) & ~np.isnan(l) & ~np.isnan(r) &
                            (m <= threshold) & (m-l < 0) & (r-m > 0))[0] + 1
        if len(minima) is 0:
            print(u'Channel %d: no epochs found using threshold %g' % (
                i, threshold))
            allchannels_epochs.append([])
        else:
            # Sort the list of minima by ascending variability
            minima = minima[np.argsort(v[minima])]
            epochs = []
            for m in minima:
                # Check this minimum is not inside an existing epoch
                overlap = False
                for e in epochs:
                    if m >= e[0] and m <= e[1]:
                        overlap = True
                        break
                if not overlap:
                    # Get largest subthreshold interval surrounding the minimum
                    startix = m - 1
                    endix = m + 1
                    for startix in range(m - 1, 0, -1):
                        if np.isnan(v[startix]) or v[startix] > threshold:
                            startix += 1
                            break
                    for endix in range(m + 1, len(v), 1):
                        if np.isnan(v[endix]) or v[endix] > threshold:
                            break
                    if (endix - startix) * dt >= minlength:
                        epochs.append((startix, endix))
            allchannels_epochs.append(epochs)
    if plot:
        _plot_variability(ts, variability, threshold, allchannels_epochs)
    if orig_ndim is 1:
        allchannels_epochs = allchannels_epochs[0]
    return (variability, allchannels_epochs)

Response: Identify stationary epochs within a time series.


Instruction:
Implement a function in Python 3 to
distribute epochs for a time series.

Response:
def epochs_distributed(ts, variability=None, threshold=0.0, minlength=1.0,
                       plot=True):
    """Same as `epochs()`, but computes channels in parallel for speed.

    (Note: This requires an IPython cluster to be started first,
           e.g. on a workstation type 'ipcluster start')

    Identify "stationary" epochs within a time series, based on a
    continuous measure of variability.
    Epochs are defined to contain the points of minimal variability, and to
    extend as wide as possible with variability not exceeding the threshold.

    Args:
      ts  Timeseries of m variables, shape (n, m).
      variability  (optional) Timeseries of shape (n, m, q),  giving q scalar
                   measures of the variability of timeseries `ts` near each
                   point in time. (if None, we will use variability_fp())
                   Epochs require the mean of these to be below the threshold.
      threshold   The maximum variability permitted in stationary epochs.
      minlength   Shortest acceptable epoch length (in seconds)
      plot  bool  Whether to display the output

    Returns: (variability, allchannels_epochs)
      variability: as above
      allchannels_epochs: (list of) list of tuples
      For each variable, a list of tuples (start, end) that give the
      starting and ending indices of stationary epochs.
      (epochs are inclusive of start point but not the end point)
    """
    import distob
    if ts.ndim is 1:
        ts = ts[:, np.newaxis]
    if variability is None:
        dts = distob.scatter(ts, axis=1)
        vepochs = distob.vectorize(epochs)
        results = vepochs(dts, None, threshold, minlength, plot=False)
    else:
        def f(pair):
            return epochs(pair[0], pair[1], threshold, minlength, plot=False)
        allpairs = [(ts[:, i], variability[:, i]) for i in range(ts.shape[1])]
        vf = distob.vectorize(f)
        results = vf(allpairs)
    vars, allchannels_epochs = zip(*results)
    variability = distob.hstack(vars)
    if plot:
        _plot_variability(ts, variability, threshold, allchannels_epochs)
    return (variability, allchannels_epochs)


Instruction:
How would you code a function in Python 3 to
identify epochs within a multivariate time series where at least one of the specified variability is stationary.

Response:
def epochs_joint(ts, variability=None, threshold=0.0, minlength=1.0,
                 proportion=0.75, plot=True):
    """Identify epochs within a multivariate time series where at least a
    certain proportion of channels are "stationary", based on a previously
    computed variability measure.

    (Note: This requires an IPython cluster to be started first,
     e.g. on a workstation type 'ipcluster start')

    Args:
      ts  Timeseries of m variables, shape (n, m).
      variability  (optional) Timeseries of shape (n, m),  giving a scalar
                   measure of the variability of timeseries `ts` near each
                   point in time. (if None, we will use variability_fp())
      threshold   The maximum variability permitted in stationary epochs.
      minlength   Shortest acceptable epoch length (in seconds)
      proportion  Require at least this fraction of channels to be "stationary"
      plot  bool  Whether to display the output

    Returns: (variability, joint_epochs)
      joint_epochs: list of tuples
      A list of tuples (start, end) that give the starting and ending indices
      of time epochs that are stationary for at least `proportion` of channels.
      (epochs are inclusive of start point but not the end point)
    """
    variability, allchannels_epochs = ts.epochs_distributed(
            variability, threshold, minlength, plot=False)
    orig_ndim = ts.ndim
    if ts.ndim is 1:
        ts = ts[:, np.newaxis]
        allchannels_epochs = [allchannels_epochs]
        variability = variability[:, np.newaxis]
    channels = ts.shape[1]
    dt = (1.0*ts.tspan[-1] - ts.tspan[0]) / (len(ts) - 1)
    starts = [(e[0], 1) for channel in allchannels_epochs for e in channel]
    ends = [(e[1], -1) for channel in allchannels_epochs for e in channel]
    all = sorted(starts + ends)
    joint_epochs = []
    in_joint_epoch = False
    joint_start = 0.0
    inside_count = 0
    for bound in all:
        inside_count += bound[1]
        if not in_joint_epoch and 1.0*inside_count/channels >= proportion:
            in_joint_epoch = True
            joint_start = bound[0]
        if in_joint_epoch and 1.0*inside_count/channels < proportion:
            in_joint_epoch = False
            joint_end = bound[0]
            if (joint_end - joint_start)*dt >= minlength:
                joint_epochs.append((joint_start, joint_end))
    if plot:
        joint_epochs_repeated = [joint_epochs] * channels
        _plot_variability(ts, variability, threshold, joint_epochs_repeated)
    return (variability, joint_epochs)


Instruction:
How would you implement a function in Python 3 that
plots a Timeseries containing a single variable and a single simulation time series.

Response:
def plot(ts, title=None, show=True):
    """Plot a Timeseries
    Args:
      ts  Timeseries
      title  str
      show  bool whether to display the figure or just return a figure object
      """
    ts = _remove_pi_crossings(ts)
    fig = plt.figure()
    ylabelprops = dict(rotation=0,
                       horizontalalignment='right',
                       verticalalignment='center',
                       x=-0.01)
    if ts.ndim > 2: # multiple sim timeseries. collapse vars onto each subplot.
        num_subplots = ts.shape[ts.ndim - 1]
        if title is None:
            title = u'time series at each node'
        for i in range(num_subplots):
            ax = fig.add_subplot(num_subplots, 1, i+1)
            ax.plot(ts.tspan, ts[...,i])
            if ts.labels[-1] is not None:
                ax.set_ylabel(ts.labels[-1][i], **ylabelprops)
            else:
                ax.set_ylabel('node ' + str(i), **ylabelprops)
            plt.setp(ax.get_xticklabels(), visible=False)
        fig.axes[0].set_title(title)
        plt.setp(fig.axes[num_subplots-1].get_xticklabels(), visible=True)
        fig.axes[num_subplots-1].set_xlabel('time (s)')
    else: # single sim timeseries. show each variable separately.
        if ts.ndim is 1:
            ts = ts.reshape((-1, 1))
        num_ax = ts.shape[1]
        if title is None:
            title=u'time series'
        axprops = dict()
        if num_ax > 10:
            axprops['yticks'] = []
        colors = _get_color_list()
        for i in range(num_ax):
            rect = 0.1, 0.85*(num_ax - i - 1)/num_ax + 0.1, 0.8, 0.85/num_ax
            ax = fig.add_axes(rect, **axprops)
            ax.plot(ts.tspan, ts[...,i], color=colors[i % len(colors)])
            plt.setp(ax.get_xticklabels(), visible=False)
            if ts.labels[1] is not None:
                ax.set_ylabel(ts.labels[1][i], **ylabelprops)
        fig.axes[0].set_title(title)
        plt.setp(fig.axes[num_ax-1].get_xticklabels(), visible=True)
        fig.axes[num_ax-1].set_xlabel('time (s)')
    if show:
        fig.show()
    return fig


Instruction:
Can you generate the documentation for the following Python 3 function
def _remove_pi_crossings(ts):
    orig_ts = ts
    if ts.ndim is 1:
        ts = ts[:, np.newaxis, np.newaxis]
    elif ts.ndim is 2:
        ts = ts[:, np.newaxis]
    # Get the indices of those variables that have range of approx -pi to pi
    tsmax = ts.max(axis=0)
    tsmin = ts.min(axis=0)
    phase_vars = np.transpose(np.nonzero((np.abs(tsmax - np.pi) < 0.01) &
                                         (np.abs(tsmin + np.pi) < 0.01)))
    if len(phase_vars) is 0:
        return orig_ts
    else:
        ts = ts.copy()
        for v in phase_vars:
            ts1 = np.asarray(ts[:, v[0], v[1]]) # time series of single variable
            ts1a = ts1[0:-1]
            ts1b = ts1[1:]
            p2 = np.pi/2
            # Find time indices where phase crosses pi. Set those values to nan.
            pc = np.nonzero((ts1a > p2) & (ts1b < -p2) |
                            (ts1a < -p2) & (ts1b > p2))[0] + 1
            ts1[pc] = np.nan
            ts[:, v[0], v[1]] = ts1
        return ts

Response: Removes all pi crossings from the time series ts.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def timeseries_from_mat(filename, varname=None, fs=1.0):
    import scipy.io as sio
    if varname is None:
        mat_dict = sio.loadmat(filename)
        if len(mat_dict) > 1:
            raise ValueError('Must specify varname: file contains '
                             'more than one variable. ')
    else:
        mat_dict = sio.loadmat(filename, variable_names=(varname,))
        array = mat_dict.popitem()[1]
    return Timeseries(array, fs=fs)

Response: Load a multi - channel Timeseries from a MATLAB. mat file.


Instruction:
Given the following Python 3 function, write the documentation
def save_mat(ts, filename):
    import scipy.io as sio
    tspan = ts.tspan
    fs = (1.0*len(tspan) - 1) / (tspan[-1] - tspan[0])
    mat_dict = {'data': np.asarray(ts),
                'fs': fs,
                'labels': ts.labels[1]}
    sio.savemat(filename, mat_dict, do_compression=True)
    return

Response: save a Timeseries to a MATLAB. mat file


Instruction:
Can you implement a function in Python 3 that
loads a multi - channel Timeseries from a file.

Response:
def timeseries_from_file(filename):
    """Load a multi-channel Timeseries from any file type supported by `biosig`

    Supported file formats include EDF/EDF+, BDF/BDF+, EEG, CNT and GDF.
    Full list is here: http://pub.ist.ac.at/~schloegl/biosig/TESTED

    For EDF, EDF+, BDF and BDF+ files, we will use python-edf
    if it is installed, otherwise will fall back to python-biosig.

    Args:
      filename

    Returns:
      Timeseries
    """
    if not path.isfile(filename):
        raise Error("file not found: '%s'" % filename)
    is_edf_bdf = (filename[-4:].lower() in ['.edf', '.bdf'])
    if is_edf_bdf:
        try:
            import edflib
            return _load_edflib(filename)
        except ImportError:
            print('python-edf not installed. trying python-biosig instead...')
    try:
        import biosig
        return _load_biosig(filename)
    except ImportError:
        message = (
            """To load timeseries from file, ensure python-biosig is installed
            e.g. on Ubuntu or Debian type `apt-get install python-biosig`
            or get it from http://biosig.sf.net/download.html""")
        if is_edf_bdf:
            message += """\n(For EDF/BDF files, can instead install python-edf:
                       https://bitbucket.org/cleemesser/python-edf/ )"""
        raise Error(message)


Instruction:
Create a Python 3 function for
loading a multi - channel Timeseries from an EDF file using edflib.

Response:
def _load_edflib(filename):
    """load a multi-channel Timeseries from an EDF (European Data Format) file
    or EDF+ file, using edflib.

    Args:
      filename: EDF+ file

    Returns:
      Timeseries
    """
    import edflib
    e = edflib.EdfReader(filename, annotations_mode='all')
    if np.ptp(e.get_samples_per_signal()) != 0:
        raise Error('channels have differing numbers of samples')
    if np.ptp(e.get_signal_freqs()) != 0:
        raise Error('channels have differing sample rates')
    n = e.samples_in_file(0)
    m = e.signals_in_file
    channelnames = e.get_signal_text_labels()
    dt = 1.0/e.samplefrequency(0)
    # EDF files hold <=16 bits of information for each sample. Representing as
    # double precision (64bit) is unnecessary use of memory. use 32 bit float:
    ar = np.zeros((n, m), dtype=np.float32)
    # edflib requires input buffer of float64s
    buf = np.zeros((n,), dtype=np.float64)
    for i in range(m):
        e.read_phys_signal(i, 0, n, buf)
        ar[:,i] = buf
    tspan = np.arange(0, (n - 1 + 0.5) * dt, dt, dtype=np.float32)
    return Timeseries(ar, tspan, labels=[None, channelnames])


Instruction:
Can you generate the documentation for the following Python 3 function
def annotations_from_file(filename):
    import edflib
    e = edflib.EdfReader(filename, annotations_mode='all')
    return e.read_annotations()

Response: Get a list of event annotations from an EDF file using edflib.


Instruction:
Explain what the following Python 3 code does
def _ufunc_wrap(out_arr, ufunc, method, i, inputs, **kwargs):
    # Assigns tspan/labels to an axis only if inputs do not disagree on them.
    shape = out_arr.shape
    ndim = out_arr.ndim
    if ndim is 0 or shape[0] is 0:
        # not a timeseries
        return out_arr
    candidates = [a.tspan for a in inputs if (hasattr(a, 'tspan') and
                                              a.shape[0] == shape[0])]
    # Expensive to validate all tspans are the same. check start and end t
    starts = [tspan[0] for tspan in candidates]
    ends = [tspan[-1] for tspan in candidates]
    if len(set(starts)) != 1 or len(set(ends)) != 1:
        # inputs cannot agree on tspan
        return out_arr
    else:
        new_tspan = candidates[0]
    new_labels = [None]
    for i in range(1, ndim):
        candidates = [a.labels[i] for a in inputs if (hasattr(a, 'labels') and
                 a.shape[i] == shape[i] and a.labels[i] is not None)]
        if len(candidates) is 1:
            new_labels.append(candidates[0])
        elif (len(candidates) > 1 and all(labs[j] == candidates[0][j] for
                labs in candidates[1:] for j in range(shape[i]))):
            new_labels.append(candidates[0])
        else:
            new_labels.append(None)
    if isinstance(out_arr, np.ndarray):
        return Timeseries(out_arr, new_tspan, new_labels)
    elif isinstance(out_arr, distob.RemoteArray):
        return _rts_from_ra(out_arr, new_tspan, new_labels)
    elif (isinstance(out_arr, distob.DistArray) and
          all(isinstance(ra, RemoteTimeseries) for ra in out_arr._subarrays)):
        return _dts_from_da(out_arr, new_tspan, new_labels)
    else:
        return out_arr

Response: This function wraps the ufunc function in a Timeseries and DistTimeseries instance.


Instruction:
Write a Python 3 function for
constructing a RemoteTimeseries from a RemoteArray

Response:
def _rts_from_ra(ra, tspan, labels, block=True):
    """construct a RemoteTimeseries from a RemoteArray"""
    def _convert(a, tspan, labels):
        from nsim import Timeseries
        return Timeseries(a, tspan, labels)
    return distob.call(
            _convert, ra, tspan, labels, prefer_local=False, block=block)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _dts_from_da(da, tspan, labels):
    sublabels = labels[:]
    new_subarrays = []
    for i, ra in enumerate(da._subarrays):
        if isinstance(ra, RemoteTimeseries):
            new_subarrays.append(ra)
        else:
            if labels[da._distaxis]:
                sublabels[da._distaxis] = labels[da._distaxis][
                        da._si[i]:da._si[i+1]]
            new_subarrays.append(_rts_from_ra(ra, tspan, sublabels, False))
    new_subarrays = [distob.convert_result(ar) for ar in new_subarrays]
    da._subarrays = new_subarrays
    da.__class__ = DistTimeseries
    da.tspan = tspan
    da.labels = labels
    da.t = _Timeslice(da)
    return da

Response: construct a DistTimeseries from a DistArray


Instruction:
Can you create a Python 3 function that
makes a simulation of the system defined by functions f and G.

Response:
def newsim(f, G, y0, name='NewModel', modelType=ItoModel, T=60.0, dt=0.005, repeat=1, identical=True):
    """Make a simulation of the system defined by functions f and G.

    dy = f(y,t)dt + G(y,t).dW with initial condition y0
    This helper function is for convenience, making it easy to define
    one-off simulations interactively in ipython.

    Args:
      f: callable(y, t) (defined in global scope) returning (n,) array
        Vector-valued function to define the deterministic part of the system
      G: callable(y, t) (defined in global scope) returning (n,m) array
        Optional matrix-valued function to define noise coefficients of an Ito
        SDE system.
      y0 (array):  Initial condition
      name (str): Optional class name for the new model
      modelType (type): The type of model to simulate. Must be a subclass of
        nsim.Model, for example nsim.ODEModel, nsim.ItoModel or
        nsim.StratonovichModel. The default is nsim.ItoModel.
      T: Total length of time to simulate, in seconds.
      dt: Timestep for numerical integration.
      repeat (int, optional)
      identical (bool, optional)

    Returns:
      Simulation

    Raises:
      SimValueError, SimTypeError
    """
    NewModel = newmodel(f, G, y0, name, modelType)
    if repeat == 1:
        return Simulation(NewModel(), T, dt)
    else:
        return RepeatedSim(NewModel, T, dt, repeat, identical)


Instruction:
Write a Python 3 script for
using the functions f and G to define a new Model class for simulations. It will take functions f and G from global scope and make a new Model class out of them. It will automatically gather any globals used in the definition of f and G and turn them into attributes of the new Model. Args: f: callable(y, t) (defined in global scope) returning (n,) array Scalar or vector-valued function to define the deterministic part G: callable(y, t) (defined in global scope) returning (n,m) array Optional scalar or matrix-valued function to define noise coefficients of a stochastic system. This should be ``None`` for an ODE system. y0 (Number or array): Initial condition name (str): Optional class name for the new model modelType (type): The type of model to simulate. Must be a subclass of nsim.Model, for example nsim.ODEModel, nsim.ItoModel or nsim.StratonovichModel. The default is nsim.ItoModel. Returns: new class (subclass of Model) Raises: SimValueError, SimTypeError

Response:
def newmodel(f, G, y0, name='NewModel', modelType=ItoModel):
    """Use the functions f and G to define a new Model class for simulations.

    It will take functions f and G from global scope and make a new Model class
    out of them. It will automatically gather any globals used in the definition
    of f and G and turn them into attributes of the new Model.

    Args:
      f: callable(y, t) (defined in global scope) returning (n,) array
         Scalar or vector-valued function to define the deterministic part
      G: callable(y, t) (defined in global scope) returning (n,m) array
         Optional scalar or matrix-valued function to define noise coefficients
         of a stochastic system. This should be ``None`` for an ODE system.
      y0 (Number or array): Initial condition
      name (str): Optional class name for the new model
      modelType (type): The type of model to simulate. Must be a subclass of
        nsim.Model, for example nsim.ODEModel, nsim.ItoModel or
        nsim.StratonovichModel. The default is nsim.ItoModel.

    Returns:
      new class (subclass of Model)

    Raises:
      SimValueError, SimTypeError
    """
    if not issubclass(modelType, Model):
        raise SimTypeError('modelType must be a subclass of nsim.Model')
    if not callable(f) or (G is not None and not callable(G)):
        raise SimTypeError('f and G must be functions of y and t.')
    if G is not None and f.__globals__ is not G.__globals__:
        raise SimValueError('f and G must be defined in the same place')
    # TODO: validate that f and G are defined at global scope.
    # TODO: Handle nonlocals used in f,G so that we can lift this restriction.
    if modelType is ODEModel and G is not None and not np.all(G == 0.0):
        raise SimValueError('For an ODEModel, noise matrix G should be None')
    if G is None or modelType is ODEModel:
        newclass = type(name, (ODEModel,), dict())
        setattr(newclass, 'f', staticmethod(__clone_function(f, 'f')))
    else:
        newclass = type(name, (modelType,), dict())
        setattr(newclass, 'f', staticmethod(__clone_function(f, 'f')))
        setattr(newclass, 'G', staticmethod(__clone_function(G, 'G')))
    setattr(newclass, 'y0', copy.deepcopy(y0))
    # For any global that is used by the functions f or G, create a
    # corresponding attribute in our new class.
    globals_used = [x for x in f.__globals__ if (x in f.__code__.co_names or
        G is not None and x in G.__code__.co_names)]
    for x in globals_used:
        if G is None:
            setattr(newclass, x, __AccessDict(x, newclass.f.__globals__))
        else:
            setattr(newclass, x, __AccessDicts(x, newclass.f.__globals__,
                                                  newclass.G.__globals__))
    # Put the new class into namespace __main__ (to cause dill to pickle it)
    newclass.__module__ = '__main__'
    import __main__
    __main__.__dict__[name] = newclass
    return newclass


Instruction:
Can you implement a function in Python 3 that
makes a new version of a function that has its own independent copy of any globals that it uses directly and has its own independent copy of any globals that it uses directly and has its own name assigned from the original function.

Response:
def __clone_function(f, name=None):
    """Make a new version of a function that has its own independent copy
    of any globals that it uses directly, and has its own name.
    All other attributes are assigned from the original function.

    Args:
      f: the function to clone
      name (str):  the name for the new function (if None, keep the same name)

    Returns:
      A copy of the function f, having its own copy of any globals used

    Raises:
      SimValueError
    """
    if not isinstance(f, types.FunctionType):
        raise SimTypeError('Given parameter is not a function.')
    if name is None:
        name = f.__name__
    newglobals = f.__globals__.copy()
    globals_used = [x for x in f.__globals__ if x in f.__code__.co_names]
    for x in globals_used:
        gv = f.__globals__[x]
        if isinstance(gv, types.FunctionType):
            # Recursively clone any global functions used by this function.
            newglobals[x] = __clone_function(gv)
        elif isinstance(gv, types.ModuleType):
            newglobals[x] = gv
        else:
            # If it is something else, deep copy it.
            newglobals[x] = copy.deepcopy(gv)
    newfunc = types.FunctionType(
        f.__code__, newglobals, name, f.__defaults__, f.__closure__)
    return newfunc


Instruction:
Make a summary of the following Python 3 code
def expand_dims(self, axis):
        if axis <= self._distaxis:
            subaxis = axis
            new_distaxis = self._distaxis + 1
        else:
            subaxis = axis - 1
            new_distaxis = self._distaxis
        new_subts = [rts.expand_dims(subaxis) for rts in self._subarrays]
        if axis == 0:
            # prepended an axis: no longer a Timeseries
            return distob.DistArray(new_subts, new_distaxis)
        else:
            axislabels = self.labels[self._distaxis]
            return DistTimeseries(new_subts, new_distaxis, axislabels)

Response: Insert a new axis at a given position in the array shape.


Instruction:
Can you write a function in Python 3 where it
calculates the absolute value element - wise.

Response:
def absolute(self):
        """Calculate the absolute value element-wise.

        Returns:
          absolute (Timeseries):
            Absolute value. For complex input (a + b*j) gives sqrt(a**a + b**2)
        """
        da = distob.vectorize(np.absolute)(self)
        return _dts_from_da(da, self.tspan, self.labels)


Instruction:
Create a Python 3 function to
return the angle of a complex Timeseries

Response:
def angle(self, deg=False):
        """Return the angle of a complex Timeseries

        Args:
          deg (bool, optional):
            Return angle in degrees if True, radians if False (default).

        Returns:
          angle (Timeseries):
            The counterclockwise angle from the positive real axis on
            the complex plane, with dtype as numpy.float64.
        """
        if self.dtype.str[1] != 'c':
            warnings.warn('angle() is intended for complex-valued timeseries',
                          RuntimeWarning, 1)
        da = distob.vectorize(np.angle)(self, deg)
        return _dts_from_da(da, self.tspan, self.labels)


Instruction:
Can you generate the documentation for the following Python 3 function
def coupling(self, source_y, target_y, weight):
        return np.ones_like(target_y)*np.mean(source_y)*weight

Response: This example coupling function is used to couple the output of one subsystem to the input of another subsystem.


Instruction:
Given the following Python 3 function, write the documentation
def f(self, y, t):
        coupling = self.coupling_function[0]
        res = np.empty_like(self.y0)
        for j, m in enumerate(self.submodels):
            slicej = slice(self._si[j], self._si[j+1])
            target_y = y[slicej] # target node state
            res[slicej] = m.f(target_y, t) # deterministic part of submodel j
            # get indices of all source nodes that provide input to node j:
            sources = np.nonzero(self.network[:,j])[0]
            for i in sources:
                weight = self.network[i, j]
                source_y = y[slice(self._si[i], self._si[i+1])] # source state
                res[slicej] += coupling(source_y, target_y, weight)
        return res

Response: Deterministic term f of the complete network system.


Instruction:
Can you write a function in Python 3 where it
noises coefficient matrix G of the complete network system.

Response:
def G(self, y, t):
        """Noise coefficient matrix G of the complete network system
        dy = f(y, t)dt + G(y, t).dot(dW)

        (for an ODE network system without noise this function is not used)

        Args:
          y (array of shape (d,)): where d is the dimension of the overall
            state space of the complete network system.

        Returns:
          G (array of shape (d, m)): where m is the number of independent
            Wiener processes driving the complete network system. The noise
            coefficient matrix G defines the stochastic term of the system.
        """
        if self._independent_noise:
            # then G matrix consists of submodel Gs diagonally concatenated:
            res = np.zeros((self.dimension, self.nnoises))
            offset = 0
            for j, m in enumerate(self.submodels):
                slicej = slice(self._si[j], self._si[j+1])
                ix = (slicej, slice(offset, offset + self._nsubnoises[j]))
                res[ix] = m.G(y[slicej], t) # submodel noise coefficient matrix
                offset += self._nsubnoises[j]
        else:
            # identical driving: G consists of submodel Gs stacked vertically
            res = np.empty((self.dimension, self.nnoises))
            for j, m in enumerate(self.submodels):
                slicej = slice(self._si[j], self._si[j+1])
                ix = (slicej, slice(None))
                res[ix] = m.G(y[slicej], t) # submodel noise coefficient matrix
        return res


Instruction:
Can you implement a function in Python 3 that
converts a scalar model to 1D vector systems.

Response:
def _scalar_to_vector(self, m):
        """Allow submodels with scalar equations. Convert to 1D vector systems.
        Args:
          m (Model)
        """
        if not isinstance(m.y0, numbers.Number):
            return m
        else:
            m = copy.deepcopy(m)
            t0 = 0.0
            if isinstance(m.y0, numbers.Integral):
                numtype = np.float64
            else:
                numtype = type(m.y0)
            y0_orig = m.y0
            m.y0 = np.array([m.y0], dtype=numtype)
            def make_vector_fn(fn):
                def newfn(y, t):
                    return np.array([fn(y[0], t)], dtype=numtype)
                newfn.__name__ = fn.__name__
                return newfn
            def make_matrix_fn(fn):
                def newfn(y, t):
                    return np.array([[fn(y[0], t)]], dtype=numtype)
                newfn.__name__ = fn.__name__
                return newfn
            def make_coupling_fn(fn):
                def newfn(source_y, target_y, weight):
                    return np.array([fn(source_y[0], target_y[0], weight)])
                newfn.__name__ = fn.__name__
                return newfn
            if isinstance(m.f(y0_orig, t0), numbers.Number):
                m.f = make_vector_fn(m.f)
            if hasattr(m, 'G') and isinstance(m.G(y0_orig,t0), numbers.Number):
                m.G = make_matrix_fn(m.G)
            if (hasattr(m, 'coupling') and
                    isinstance(m.coupling(y0_orig, y0_orig, 0.5),
                               numbers.Number)):
                m.coupling = make_coupling_fn(m.coupling)
            return m


Instruction:
Explain what the following Python 3 code does
def _reshape_timeseries(self, ts):
        if np.count_nonzero(np.diff(self._sublengths)) == 0:
            # then all submodels have the same dimension, so can reshape array
            # in place without copying data:
            subdim = self.dimension // self._n
            shp = list(ts.shape)
            shp[1] = self._n
            shp.insert(2, subdim)
            ts = ts.reshape(tuple(shp)).swapaxes(1, 2)
            # label variables only if all sub-models agree on the labels:
            all_var_labels = [m.labels for m in self.submodels]
            var_labels = all_var_labels[0]
            if all(v == var_labels for v in all_var_labels[1:]):
                ts.labels[1] = var_labels
            ts.labels[2] = self._node_labels()
            return ts
        else:
            # will pad with zeros for submodels with less variables
            subdim = max(self._sublengths)
            shp = list(ts.shape)
            shp[1] = subdim
            shp.insert(2, self._n)
            ar = np.zeros(shp)
            labels = ts.labels
            labels.insert(2, self._node_labels())
            for k in range(self._n):
                sl = slice(self._si[k], self._si[k+1])
                ar[:,:,k,...] = ts[:,sl,...]
            return Timeseries(ar, ts.tspan, labels)

Response: Introduce a new axis 2 that ranges across nodes of the network


Instruction:
Create a Python 3 function to
introduce a new axis 2 that ranges across nodes of the network

Response:
def _reshape_output(self, ts):
        """Introduce a new axis 2 that ranges across nodes of the network"""
        subodim = len(self.submodels[0].output_vars)
        shp = list(ts.shape)
        shp[1] = subodim
        shp.insert(2, self._n)
        ts = ts.reshape(tuple(shp))
        ts.labels[2] = self._node_labels()
        return ts


Instruction:
Make a summary of the following Python 3 code
def output(self):
        subts = [s.output for s in self.sims]
        sub_ndim = subts[0].ndim
        if sub_ndim is 1:
            subts = [distob.expand_dims(ts, 1) for ts in subts]
            sub_ndim += 1
        nodeaxis = sub_ndim
        subts = [distob.expand_dims(ts, nodeaxis) for ts in subts]
        ts = subts[0].concatenate(subts[1:], axis=nodeaxis)
        ts.labels[nodeaxis] = self._node_labels()
        return ts

Response: Rank 3 array representing output time series. Axis 0 is time axis 1 ranges across output variables of a single simulation instance axis 2 ranges across different simulation instances.


Instruction:
Write a Python 3 function for
giving an integer index ix into the list of sims returns the relevant subsim and subindex into s where s is the relevant subsim and m is the relevant subindex into s where s is the relevant subsim.

Response:
def _tosub(self, ix):
        """Given an integer index ix into the list of sims, returns the pair
        (s, m) where s is the relevant subsim and m is the subindex into s.
        So self[ix] == self._subsims[s][m]
        """
        N = self._n
        if ix >= N or ix < -N:
            raise IndexError(
                    'index %d out of bounds for list of %d sims' % (ix, N))
        if ix < 0:
            ix += N
        for s in range(0, self._n):
            if self._si[s + 1] - 1 >= ix:
                break
        m = ix - self._si[s]
        return s, m


Instruction:
Can you tell what is the following Python 3 function doing
def _tosubs(self, ixlist):
        n = len(ixlist)
        N = self._n
        ss = []
        ms = []
        if n == 0:
            return ss, ms
        j = 0 # the position in ixlist currently being processed
        ix = ixlist[j]
        if ix >= N or ix < -N:
            raise IndexError(
                    'index %d out of bounds for list of %d sims' % (ix, N))
        if ix < 0:
            ix += N
        while j < n:
            for s in range(0, self._n):
                low = self._si[s]
                high = self._si[s + 1]
                if ix >= low and ix < high:
                    ss.append(s)
                    msj = [ix - low]
                    j += 1
                    while j < n:
                        ix = ixlist[j]
                        if ix >= N or ix < -N:
                            raise IndexError(
                              'index %d out of bounds for list of %d sims' % (
                                ix, N))
                        if ix < 0:
                            ix += N
                        if ix < low or ix >= high:
                            break
                        msj.append(ix - low)
                        j += 1
                    ms.append(msj)
                if ix < low:
                    break
        return ss, ms

Response: Maps a list of integer indices to sub - indices.


Instruction:
Can you tell what is the following Python 3 function doing
def output(self):
        subts = [rms.output for rms in self._subsims]
        distaxis = subts[0].ndim - 1
        return DistTimeseries(subts, distaxis, self._node_labels())

Response: Rank 3 array representing output time series. Axis 0 is time axis 1 ranges across output variables of a single simulation axis 2 isSetNodeCounts = True


Instruction:
Write a Python 3 script for
giving a time series ts find the times at which the value c crosses at least d.

Response:
def crossing_times(ts, c=0.0, d=0.0):
    """For a single variable timeseries, find the times at which the
    value crosses ``c`` from above or below. Can optionally set a non-zero
    ``d`` to impose the condition that the value must wander at least ``d``
    units away from ``c`` between crossings.

    If the timeseries begins (or ends) exactly at ``c``, then time zero
    (or the ending time) is also included as a crossing event,
    so that the boundaries of the first and last excursions are included.

    If the actual crossing time falls between two time steps, linear
    interpolation is used to estimate the crossing time.

    Args:
      ts: Timeseries (single variable)

      c (float): Critical value at which to report crossings.

      d (float): Optional min distance from c to be attained between crossings.

    Returns:
      array of float
    """
    #TODO support multivariate time series
    ts = ts.squeeze()
    if ts.ndim is not 1:
        raise ValueError('Currently can only use on single variable timeseries')

    # Translate to put the critical value at zero:
    ts = ts - c

    tsa = ts[0:-1]
    tsb = ts[1:]
    # Time indices where phase crosses or reaches zero from below or above
    zc = np.nonzero((tsa < 0) & (tsb >= 0) | (tsa > 0) & (tsb <= 0))[0] + 1
    # Estimate crossing time interpolated linearly within a single time step
    va = ts[zc-1]
    vb = ts[zc]
    ct = (np.abs(vb)*ts.tspan[zc-1] +
          np.abs(va)*ts.tspan[zc]) / np.abs(vb - va) # denominator always !=0
    # Also include starting time if we started exactly at zero
    if ts[0] == 0.0:
        zc = np.r_[np.array([0]), zc]
        ct = np.r_[np.array([ts.tspan[0]]), ct]

    if d == 0.0 or ct.shape[0] is 0:
        return ct

    # Time indices where value crosses c+d or c-d:
    dc = np.nonzero((tsa < d) & (tsb >= d) | (tsa > -d) & (tsb <= -d))[0] + 1
    # Select those zero-crossings separated by at least one d-crossing
    splice = np.searchsorted(dc, zc)
    which_zc = np.r_[np.array([0]), np.nonzero(splice[0:-1] - splice[1:])[0] +1]
    return ct[which_zc]


Instruction:
Can you generate the documentation for the following Python 3 function
def autocorrelation(ts, normalized=False, unbiased=False):
    ts = np.squeeze(ts)
    if ts.ndim <= 1:
        if normalized:
            ts = (ts - ts.mean())/ts.std()
        N = ts.shape[0]
        ar = np.asarray(ts)
        acf = np.correlate(ar, ar, mode='full')
        outlen = (acf.shape[0] + 1) / 2
        acf = acf[(outlen - 1):]
        if unbiased:
            factor = np.array([1.0/(N - m) for m in range(0, outlen)])
            acf = acf * factor
        dt = (ts.tspan[-1] - ts.tspan[0]) / (len(ts) - 1.0)
        lags = np.arange(outlen)*dt
        return Timeseries(acf, tspan=lags, labels=ts.labels)
    else:
        # recursively handle arrays of dimension > 1
        lastaxis = ts.ndim - 1
        m = ts.shape[lastaxis]
        acfs = [ts[...,i].autocorrelation(normalized, unbiased)[...,np.newaxis]
                for i in range(m)]
        res = distob.concatenate(acfs, axis=lastaxis)
        res.labels[lastaxis] = ts.labels[lastaxis]
        return res

Response: Returns the discrete linear convolution of a time series with itself optionally using unbiased normalization.


Instruction:
Here you have a function in Python 3, explain what it does
def fan_speed(self, value):
        if value not in range(1, 10):
            raise exceptions.RoasterValueError

        self._fan_speed.value = value

Response: Verifies the value is between 1 and 9 inclusively.


Instruction:
Explain what the following Python 3 code does
def heat_setting(self, value):
        if value not in range(0, 4):
            raise exceptions.RoasterValueError

        self._heat_setting.value = value

Response: Verifies that the heat setting is between 0 and 3.


Instruction:
How would you explain what the following Python 3 function does
def heater_level(self, value):
        if self._ext_sw_heater_drive:
            if value not in range(0, self._heater_bangbang_segments+1):
                raise exceptions.RoasterValueError
            self._heater_level.value = value
        else:
            raise exceptions.RoasterValueError

Response: Verifies that the heater_level is between 0 and heater_segments. Will throw RoasterValueError otherwise.


Instruction:
How would you code a function in Python 3 to
set the state transition function for every available freshroastsr700 state.

Response:
def set_state_transition_func(self, func):
        """THIS FUNCTION MUST BE CALLED BEFORE CALLING
        freshroastsr700.auto_connect().

        Set, or re-set, the state transition function callback.
        The supplied function will be called from a separate thread within
        freshroastsr700, triggered by a separate, internal child process.
        This function will fail if the freshroastsr700 device is already
        connected to hardware, because by that time, the timer process
        and thread have already been spawned.

        Args:
            state_transition_func (func): the function to call for every
            state transition.  A state transition occurs whenever the
            freshroastsr700's time_remaining value counts down to 0.

        Returns:
            nothing
       """
        if self._connected.value:
            logging.error("freshroastsr700.set_state_transition_func must be "
                          "called before freshroastsr700.auto_connect()."
                          " Not registering func.")
            return False
        # no connection yet. so OK to set func pointer
        self._create_state_transition_system(func)
        return True


Instruction:
Can you tell what is the following Python 3 function doing
def update_data_run(self, event_to_wait_on):
        # with the daemon=Turue setting, this thread should
        # quit 'automatically'
        while event_to_wait_on.wait():
            event_to_wait_on.clear()
            if self.update_data_callback_kill_event.is_set():
                return
            self.update_data_func()

Response:
This is the main thread that listens to an event from
           the comm process to execute the update_data_func callback
           in the context of the main process.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def state_transition_run(self, event_to_wait_on):
        # with the daemon=Turue setting, this thread should
        # quit 'automatically'
        while event_to_wait_on.wait():
            event_to_wait_on.clear()
            if self.state_transition_callback_kill_event.is_set():
                return
            self.state_transition_func()

Response:
This is the main thread that listens to an event from
           the state_transition_func callback
           is called when the state_transition_func is called.


Instruction:
Make a summary of the following Python 3 code
def _connect(self):
        # the following call raises a RoasterLookupException when the device
        # is not found. It is
        port = utils.find_device('1A86:5523')
        # on some systems, after the device port is added to the device list,
        # it can take up to 20 seconds after USB insertion for
        # the port to become available... (!)
        # let's put a safety timeout in here as a precaution
        wait_timeout = time.time() + 40.0  # should be PLENTY of time!
        # let's update the _connect_state while we're at it...
        self._connect_state.value = self.CS_CONNECTING
        connect_success = False
        while time.time() < wait_timeout:
            try:
                self._ser = serial.Serial(
                    port=port,
                    baudrate=9600,
                    bytesize=8,
                    parity='N',
                    stopbits=1.5,
                    timeout=0.25,
                    xonxoff=False,
                    rtscts=False,
                    dsrdtr=False)
                connect_success = True
                break
            except serial.SerialException:
                time.sleep(0.5)
        if not connect_success:
            # timeout on attempts
            raise exceptions.RoasterLookupError

        self._initialize()

Response: Connect to the roaster and creates a communication thread.


Instruction:
Here you have a function in Python 3, explain what it does
def _initialize(self):
        self._header.value = b'\xAA\x55'
        self._current_state.value = b'\x00\x00'
        s = self._generate_packet()
        self._ser.write(s)
        self._header.value = b'\xAA\xAA'
        self._current_state.value = b'\x02\x01'

        return self._read_existing_recipe()

Response: Sends the initialization packet to the roaster.


Instruction:
Make a summary of the following Python 3 code
def connect(self):
        self._start_connect(self.CA_SINGLE_SHOT)
        while(self._connect_state.value == self.CS_ATTEMPTING_CONNECT or
              self._connect_state.value == self.CS_CONNECTING):
            time.sleep(0.1)
        if self.CS_CONNECTED != self._connect_state.value:
            raise exceptions.RoasterLookupError

Response: Attempts to connect to the computer immediately. Will not retry.


Instruction:
Make a summary of the following Python 3 code
def _start_connect(self, connect_type):
        if self._connect_state.value != self.CS_NOT_CONNECTED:
            # already done or in process, assume success
            return

        self._connected.value = 0
        self._connect_state.value = self.CS_ATTEMPTING_CONNECT
        # tell comm process to attempt connection
        self._attempting_connect.value = connect_type

        # EXTREMELY IMPORTANT - for this to work at all in Windows,
        # where the above processes are spawned (vs forked in Unix),
        # the thread objects (as sattributes of this object) must be
        # assigned to this object AFTER we have spawned the processes.
        # That way, multiprocessing can pickle the freshroastsr700
        # successfully. (It can't pickle thread-related stuff.)
        if self.update_data_func is not None:
            # Need to launch the thread that will listen to the event
            self._create_update_data_system(
                None, setFunc=False, createThread=True)
            self.update_data_thread.start()
        if self.state_transition_func is not None:
            # Need to launch the thread that will listen to the event
            self._create_state_transition_system(
                None, setFunc=False, createThread=True)
            self.state_transition_thread.start()

Response: Starts the connection process.


Instruction:
Can you create a Python 3 function that
attempts to connect to the roaster every quarter of a second. Returns True if successful False otherwise.

Response:
def _auto_connect(self):
        """Attempts to connect to the roaster every quarter of a second."""
        while not self._teardown.value:
            try:
                self._connect()
                return True
            except exceptions.RoasterLookupError:
                time.sleep(.25)
        return False


Instruction:
Create a Python 3 function to
do not call this directly - call auto_connect(), which will spawn comm() for you. This is the main communications loop to the roaster. whenever a valid packet is received from the device, if an update_data_event is available, it will be signalled. Args: thermostat (bool): thermostat mode. if set to True, turns on thermostat mode. In thermostat mode, freshroastsr700 takes control of heat_setting and does software PID control to hit the demanded target_temp. ext_sw_heater_drive (bool): enable direct control over the internal heat_controller object. Defaults to False. When set to True, the thermostat field is IGNORED, and assumed to be False. Direct control over the software heater_level means that the PID controller cannot control the heater. Since thermostat and ext_sw_heater_drive cannot be allowed to both be True, this arg is given precedence over the thermostat arg. kp (float): Kp value to use for PID control. Defaults to 0.06. ki (float): Ki value to use for PID control. Defaults to 0.0075. kd (float): Kd value to use for PID control. Defaults to 0.01. heater_segments (int): the pseudo-control range for the internal heat_controller object. Defaults to 8. update_data_event (multiprocessing.Event): If set, allows the comm_process to signal to the parent process that new device data is available. Returns: nothing

Response:
def _comm(self, thermostat=False,
              kp=0.06, ki=0.0075, kd=0.01,
              heater_segments=8, ext_sw_heater_drive=False,
              update_data_event=None):
        """Do not call this directly - call auto_connect(), which will spawn
        comm() for you.

        This is the main communications loop to the roaster.
        whenever a valid packet is received from the device, if an
        update_data_event is available, it will be signalled.

        Args:
            thermostat (bool): thermostat mode.
            if set to True, turns on thermostat mode.  In thermostat
            mode, freshroastsr700 takes control of heat_setting and does
            software PID control to hit the demanded target_temp.

            ext_sw_heater_drive (bool): enable direct control over the internal
            heat_controller object.  Defaults to False. When set to True, the
            thermostat field is IGNORED, and assumed to be False.  Direct
            control over the software heater_level means that the
            PID controller cannot control the heater.  Since thermostat and
            ext_sw_heater_drive cannot be allowed to both be True, this arg
            is given precedence over the thermostat arg.

            kp (float): Kp value to use for PID control. Defaults to 0.06.

            ki (float): Ki value to use for PID control. Defaults to 0.0075.

            kd (float): Kd value to use for PID control. Defaults to 0.01.

            heater_segments (int): the pseudo-control range for the internal
            heat_controller object.  Defaults to 8.

            update_data_event (multiprocessing.Event): If set, allows the
            comm_process to signal to the parent process that new device data
            is available.

        Returns:
            nothing
        """
        # since this process is started with daemon=True, it should exit
        # when the owning process terminates. Therefore, safe to loop forever.
        while not self._teardown.value:

            # waiting for command to attempt connect
            # print( "waiting for command to attempt connect")
            while self._attempting_connect.value == self.CA_NONE:
                time.sleep(0.25)
                if self._teardown.value:
                    break
            # if we're tearing down, bail now.
            if self._teardown.value:
                break

            # we got the command to attempt to connect
            # change state to 'attempting_connect'
            self._connect_state.value = self.CS_ATTEMPTING_CONNECT
            # attempt connection
            if self.CA_AUTO == self._attempting_connect.value:
                # this call will block until a connection is achieved
                # it will also set _connect_state to CS_CONNECTING
                # if appropriate
                if self._auto_connect():
                    # when we unblock, it is an indication of a successful
                    # connection
                    self._connected.value = 1
                    self._connect_state.value = self.CS_CONNECTED
                else:
                    # failure, normally due to a timeout
                    self._connected.value = 0
                    self._connect_state.value = self.CS_NOT_CONNECTED
                    # we failed to connect - start over from the top
                    # reset flag
                    self._attempting_connect.value = self.CA_NONE
                    continue

            elif self.CA_SINGLE_SHOT == self._attempting_connect.value:
                # try once, now, if failure, start teh big loop over
                try:
                    self._connect()
                    self._connected.value = 1
                    self._connect_state.value = self.CS_CONNECTED
                except exceptions.RoasterLookupError:
                    self._connected.value = 0
                    self._connect_state.value = self.CS_NOT_CONNECTED
                if self._connect_state.value != self.CS_CONNECTED:
                    # we failed to connect - start over from the top
                    # reset flag
                    self._attempting_connect.value = self.CA_NONE
                    continue
            else:
                # shouldn't be here
                # reset flag
                self._attempting_connect.value = self.CA_NONE
                continue

            # We are connected!
            # print( "We are connected!")
            # reset flag right away
            self._attempting_connect.value = self.CA_NONE

            # Initialize PID controller if thermostat function was specified at
            # init time
            pidc = None
            heater = None
            if(thermostat):
                pidc = pid.PID(kp, ki, kd,
                               Output_max=heater_segments,
                               Output_min=0
                               )
            if thermostat or ext_sw_heater_drive:
                heater = heat_controller(number_of_segments=heater_segments)

            read_state = self.LOOKING_FOR_HEADER_1
            r = []
            write_errors = 0
            read_errors = 0
            while not self._disconnect.value:
                start = datetime.datetime.now()
                # write to device
                if not self._write_to_device():
                    logging.error('comm - _write_to_device() failed!')
                    write_errors += 1
                    if write_errors > 3:
                        # it's time to consider the device as being "gone"
                        logging.error('comm - 3 successive write '
                                      'failures, disconnecting.')
                        self._disconnect.value = 1
                        continue
                else:
                    # reset write_errors
                    write_errors = 0

                # read from device
                try:
                    while self._ser.in_waiting:
                        _byte = self._ser.read(1)
                        read_state, r, err = (
                            self._process_reponse_byte(
                                read_state, _byte, r, update_data_event))
                except IOError:
                    # typically happens when device is suddenly unplugged
                    logging.error('comm - read from device failed!')
                    read_errors += 1
                    if write_errors > 3:
                        # it's time to consider the device as being "gone"
                        logging.error('comm - 3 successive read '
                                      'failures, disconnecting.')
                        self._disconnect.value = 1
                        continue
                else:
                    read_errors = 0

                # next, drive SW heater when using
                # thermostat mode (PID controller calcs)
                # or in external sw heater drive mode,
                # when roasting.
                if thermostat or ext_sw_heater_drive:
                    if 'roasting' == self.get_roaster_state():
                        if heater.about_to_rollover():
                            # it's time to use the PID controller value
                            # and set new output level on heater!
                            if ext_sw_heater_drive:
                                # read user-supplied value
                                heater.heat_level = self._heater_level.value
                            else:
                                # thermostat
                                output = pidc.update(
                                    self.current_temp, self.target_temp)
                                heater.heat_level = output
                                # make this number visible to other processes...
                                self._heater_level.value = heater.heat_level
                        # read bang-bang heater output array element & apply it
                        if heater.generate_bangbang_output():
                            # ON
                            self.heat_setting = 3
                        else:
                            # OFF
                            self.heat_setting = 0
                    else:
                        # for all other states, heat_level = OFF
                        heater.heat_level = 0
                        # make this number visible to other processes...
                        self._heater_level.value = heater.heat_level
                        self.heat_setting = 0

                # calculate sleep time to stick to 0.25sec period
                comp_time = datetime.datetime.now() - start
                sleep_duration = 0.25 - comp_time.total_seconds()
                if sleep_duration > 0:
                    time.sleep(sleep_duration)

            self._ser.close()
            # reset disconnect flag
            self._disconnect.value = 0
            # reset connection values
            self._connected.value = 0
            self._connect_state.value = self.CS_NOT_CONNECTED


Instruction:
Given the following Python 3 function, write the documentation
def _timer(self, state_transition_event=None):
        while not self._teardown.value:
            state = self.get_roaster_state()
            if(state == 'roasting' or state == 'cooling'):
                time.sleep(1)
                self.total_time += 1
                if(self.time_remaining > 0):
                    self.time_remaining -= 1
                else:
                    if(state_transition_event is not None):
                        state_transition_event.set()
                    else:
                        self.idle()
            else:
                time.sleep(0.01)

Response: This is the main timer loop used to keep track of the time while the roaster is in a cooling state.


Instruction:
How would you implement a function in Python 3 that
returns a string based upon the current state of the roaster. Will throw an exception if the state is unknown.

Response:
def get_roaster_state(self):
        """Returns a string based upon the current state of the roaster. Will
        raise an exception if the state is unknown.

        Returns:
            'idle' if idle,
            'sleeping' if sleeping,
            'cooling' if cooling,
            'roasting' if roasting,
            'connecting' if in hardware connection phase,
            'unknown' otherwise
        """
        value = self._current_state.value
        if(value == b'\x02\x01'):
            return 'idle'
        elif(value == b'\x04\x04'):
            return 'cooling'
        elif(value == b'\x08\x01'):
            return 'sleeping'
        # handle null bytes as empty strings
        elif(value == b'\x00\x00' or value == b''):
            return 'connecting'
        elif(value == b'\x04\x02'):
            return 'roasting'
        else:
            return 'unknown'


Instruction:
Given the following Python 3 function, write the documentation
def _generate_packet(self):
        roaster_time = utils.seconds_to_float(self._time_remaining.value)
        packet = (
            self._header.value +
            self._temp_unit.value +
            self._flags.value +
            self._current_state.value +
            struct.pack(">B", self._fan_speed.value) +
            struct.pack(">B", int(round(roaster_time * 10.0))) +
            struct.pack(">B", self._heat_setting.value) +
            b'\x00\x00' +
            self._footer)

        return packet

Response: Generates a packet based upon the current class variables.


Instruction:
Create a Python 3 function to
set the desired output level. Must be between 0 and number_of_segments inclusive.

Response:
def heat_level(self, value):
        """Set the desired output level. Must be between 0 and
        number_of_segments inclusive."""
        if value < 0:
            self._heat_level = 0
        elif round(value) > self._num_segments:
            self._heat_level = self._num_segments
        else:
            self._heat_level = int(round(value))


Instruction:
How would you explain what the following Python 3 function does
def generate_bangbang_output(self):
        if self._current_index >= self._num_segments:
            # we're due to switch over to the next
            # commanded heat_level
            self._heat_level_now = self._heat_level
            # reset array index
            self._current_index = 0
        # return output
        out = self._output_array[self._heat_level_now][self._current_index]
        self._current_index += 1
        return out

Response:
Generates the latest on or off pulse in
           the string of on or off or off.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def next_state(self):
        self.active_recipe_item += 1
        if self.active_recipe_item >= len(self.recipe):
            # we're done!
            return
        # show state step on screen
        print("--------------------------------------------")
        print("Setting next process step: %d" % self.active_recipe_item)
        print("time:%d, target: %ddegF, fan: %d, state: %s" %
              (self.recipe[self.active_recipe_item]['time_remaining'],
               self.recipe[self.active_recipe_item]['target_temp'],
               self.recipe[self.active_recipe_item]['fan_speed'],
               self.recipe[self.active_recipe_item]['state']
               ))
        print("--------------------------------------------")
        # set values for next state
        self.roaster.time_remaining = (
            self.recipe[self.active_recipe_item]['time_remaining'])
        self.roaster.target_temp = (
            self.recipe[self.active_recipe_item]['target_temp'])
        self.roaster.fan_speed = (
            self.recipe[self.active_recipe_item]['fan_speed'])
        # set state
        if(self.recipe[self.active_recipe_item]['state'] == 'roasting'):
            self.roaster.roast()
        elif(self.recipe[self.active_recipe_item]['state'] == 'cooling'):
            self.roaster.cool()
        elif(self.recipe[self.active_recipe_item]['state'] == 'idle'):
            self.roaster.idle()
        elif(self.recipe[self.active_recipe_item]['state'] == 'cooling'):
            self.roaster.sleep()

Response: This method is called when the time remaining ends. It is a method that will be called when the time remaining ends.


Instruction:
Make a summary of the following Python 3 code
def process_results(self):
        for result in self._results:
            provider = result.provider
            self.providers.append(provider)
            if result.error:
                self.failed_providers.append(provider)
                continue
            if not result.response:
                continue
            # set blacklisted to True if ip is detected with at least one dnsbl
            self.blacklisted = True
            provider_categories = provider.process_response(result.response)
            assert provider_categories.issubset(DNSBL_CATEGORIES)
            self.categories = self.categories.union(provider_categories)
            self.detected_by[provider.host] = list(provider_categories)

Response: Process results by providers and categories.


Instruction:
Write a Python 3 script for
making a DNSBL request to check the DNSBL s cache for a specific IP address.

Response:
async def dnsbl_request(self, addr, provider):
        """
        Make lookup to dnsbl provider
        Parameters:
            * addr (string) - ip address to check
            * provider (string) - dnsbl provider

        Returns:
            * DNSBLResponse object

        Raises:
            * ValueError
        """
        response = None
        error = None
        try:
            socket.inet_aton(addr)
        except socket.error:
            raise ValueError('wrong ip format')
        ip_reversed = '.'.join(reversed(addr.split('.')))
        dnsbl_query = "%s.%s" % (ip_reversed, provider.host)
        try:
            async with self._semaphore:
                response = await self._resolver.query(dnsbl_query, 'A')
        except aiodns.error.DNSError as exc:
            if exc.args[0] != 4: # 4: domain name not found:
                error = exc

        return DNSBLResponse(addr=addr, provider=provider, response=response, error=error)


Instruction:
Explain what the following Python 3 code does
def frange(start, stop, step, precision):
    value = start
    while round(value, precision) < stop:
        yield round(value, precision)
        value += step

Response: A generator that will generate a range of floats.


Instruction:
Can you generate the documentation for the following Python 3 function
def find_device(vidpid):
    for port in list_ports.comports():
        if re.search(vidpid, port[2], flags=re.IGNORECASE):
            return port[0]

    raise exceptions.RoasterLookupError

Response:
Finds a connected device with the given VID : PID. Returns the serial
    port url.


Instruction:
Can you generate the documentation for the following Python 3 function
def update(self, currentTemp, targetTemp):
        # in this implementation, ki includes the dt multiplier term,
        # and kd includes the dt divisor term.  This is typical practice in
        # industry.
        self.targetTemp = targetTemp
        self.error = targetTemp - currentTemp

        self.P_value = self.Kp * self.error
        # it is common practice to compute derivative term against PV,
        # instead of de/dt.  This is because de/dt spikes
        # when the set point changes.

        # PV version with no dPV/dt filter - note 'previous'-'current',
        # that's desired, how the math works out
        self.D_value = self.Kd * (self.Derivator - currentTemp)
        self.Derivator = currentTemp

        self.Integrator = self.Integrator + self.error
        if self.Integrator > self.Integrator_max:
            self.Integrator = self.Integrator_max
        elif self.Integrator < self.Integrator_min:
            self.Integrator = self.Integrator_min

        self.I_value = self.Integrator * self.Ki

        output = self.P_value + self.I_value + self.D_value
        if output > self.Output_max:
            output = self.Output_max
        if output < self.Output_min:
            output = self.Output_min
        return(output)

Response: Calculate PID output value for given reference input and feedback.


Instruction:
How would you implement a function in Python 3 that
loads dict from file for random words.

Response:
def load_nouns(self, file):
        """
        Load dict from file for random words.

        :param str file: filename
        """
        with open(os.path.join(main_dir, file + '.dat'), 'r') as f:
            self.nouns = json.load(f)


Instruction:
Make a summary of the following Python 3 code
def load_dmails(self, file):
        with open(os.path.join(main_dir, file + '.dat'), 'r') as f:
            self.dmails = frozenset(json.load(f))

Response: Load list of random mails from file for random mails


Instruction:
Can you write a function in Python 3 where it
loads dict from file for random nicknames.

Response:
def load_nicknames(self, file):
        """
        Load dict from file for random nicknames.

        :param str file: filename
        """
        with open(os.path.join(main_dir, file + '.dat'), 'r') as f:
            self.nicknames = json.load(f)


Instruction:
Can you generate the documentation for the following Python 3 function
def random_words(self, letter=None, count=1):
        self.check_count(count)

        words = []

        if letter is None:
            all_words = list(
                chain.from_iterable(self.nouns.values()))

            try:
                words = sample(all_words, count)
            except ValueError:
                len_sample = len(all_words)
                raise ValueError('Param "count" must be less than {0}. \
(It is only {0} words)'.format(len_sample + 1, letter))

        elif type(letter) is not str:
            raise ValueError('Param "letter" must be string.')

        elif letter not in self.available_letters:
            raise ValueError(
                'Param "letter" must be in {0}.'.format(
                    self.available_letters))

        elif letter in self.available_letters:
            try:
                words = sample(self.nouns[letter], count)
            except ValueError:
                len_sample = len(self.nouns[letter])
                raise ValueError('Param "count" must be less than {0}. \
(It is only {0} words for letter "{1}")'.format(len_sample + 1, letter))

        return words

Response: Returns a list of random words.


Instruction:
How would you code a function in Python 3 to
return a list of random nicks.

Response:
def random_nicks(self, letter=None, gender='u', count=1):
        """
        Return list of random nicks.

        :param str letter: letter
        :param str gender: ``'f'`` for female, ``'m'`` for male and None for both
        :param int count: how much nicks
        :rtype: list
        :returns: list of random nicks
        :raises: ValueError
        """
        self.check_count(count)

        nicks = []

        if gender not in ('f', 'm', 'u'):
            raise ValueError('Param "gender" must be in (f, m, u)')

        if letter is None:

            all_nicks = list(
                chain.from_iterable(self.nicknames[gender].values()))

            try:
                nicks = sample(all_nicks, count)
            except ValueError:
                len_sample = len(all_nicks)
                raise ValueError('Param "count" must be less than {0}. \
(It is only {0} words.")'.format(len_sample + 1))

        elif type(letter) is not str:
            raise ValueError('Param "letter" must be string.')

        elif letter not in self.available_letters:
            raise ValueError(
                'Param "letter" must be in "{0}".'.format(
                    self.available_letters))

        elif letter in self.available_letters:
            try:
                nicks = sample(self.nicknames[gender][letter], count)
            except ValueError:
                len_sample = len(self.nicknames[gender][letter])
                raise ValueError('Param "count" must be less than {0}. \
(It is only {0} nicks for letter "{1}")'.format(len_sample + 1, letter))

        return nicks


Instruction:
Write a Python 3 script to
return random e - mails.

Response:
def randomMails(self, count=1):
        """
        Return random e-mails.

        :rtype: list
        :returns: list of random e-mails
        """
        self.check_count(count)

        random_nicks = self.rn.random_nicks(count=count)
        random_domains = sample(self.dmails, count)

        return [
            nick.lower() + "@" + domain for nick, domain in zip(random_nicks,
                                                                random_domains)
        ]


Instruction:
Make a summary of the following Python 3 code
def get_sentences_list(self, sentences=1):
        if sentences < 1:
            raise ValueError('Param "sentences" must be greater than 0.')

        sentences_list = []

        while sentences:
            num_rand_words = random.randint(self.MIN_WORDS, self.MAX_WORDS)

            random_sentence = self.make_sentence(
                random.sample(self.words, num_rand_words))

            sentences_list.append(random_sentence)
            sentences -= 1

        return sentences_list

Response: Returns a list of sentences in the language.


Instruction:
Can you tell what is the following Python 3 function doing
def make_sentence(list_words):
        lw_len = len(list_words)

        if lw_len > 6:
            list_words.insert(lw_len // 2 + random.choice(range(-2, 2)), ',')

        sentence = ' '.join(list_words).replace(' ,', ',')

        return sentence.capitalize() + '.'

Response: Return a sentence from list of words.


Instruction:
Can you implement a function in Python 3 that
finds the cover image in the OPF file.

Response:
def _discover_cover_image(zf, opf_xmldoc, opf_filepath):
    '''
    Find the cover image path in the OPF file.
    Returns a tuple: (image content in base64, file extension)
    '''
    content = None
    filepath = None
    extension = None

    # Strategies to discover the cover-image path:

    # e.g.: <meta name="cover" content="cover"/>
    tag = find_tag(opf_xmldoc, 'meta', 'name', 'cover')
    if tag and 'content' in tag.attributes.keys():
        item_id = tag.attributes['content'].value
        if item_id:
            # e.g.: <item href="cover.jpg" id="cover" media-type="image/jpeg"/>
            filepath, extension = find_img_tag(opf_xmldoc, 'item', 'id', item_id)
    if not filepath:
        filepath, extension = find_img_tag(opf_xmldoc, 'item', 'id', 'cover-image')
    if not filepath:
        filepath, extension = find_img_tag(opf_xmldoc, 'item', 'id', 'cover')

    # If we have found the cover image path:
    if filepath:
        # The cover image path is relative to the OPF file
        base_dir = os.path.dirname(opf_filepath)
        # Also, normalize the path (ie opfpath/../cover.jpg -> cover.jpg)
        coverpath = os.path.normpath(os.path.join(base_dir, filepath))
        content = zf.read(coverpath)
        content = base64.b64encode(content)

    return content, extension