text:
import os
import collections
import csv
import difflib
import errno
import hashlib
import itertools
import logging
import math
import numpy as np
import random
import scipy
import socket
import string
import struct
import sys
import time
from itertools import chain, repeat
from numpy.fft import fft, fftshift
# from scipy import ndimage
import numpy as np
import inspect
import matplotlib.pyplot as plt
# import pyximport;pyximport.install()
import zmq

from osibase import OsiBase
from filterelement import FilterElement
# from sigmathcython import *

# converts string types to complex
def raw_to_complex(str):
    f1 = struct.unpack('%df' % 1, str[0:4])
    f2 = struct.unpack('%df' % 1, str[4:8])

    f1 = f1[0]
    f2 = f2[0]
    return f1 + f2*1j

def complex_to_raw(n):

    s1 = struct.pack('%df' % 1, np.real(n))
    s2 = struct.pack('%df' % 1, np.imag(n))

    return s1 + s2

# converts complex number to a pair of int16's, called ishort in gnuradio
def complex_to_ishort(c):
    short = 2**15-1
    re = struct.pack("h", np.real(c)*short)
    im = struct.pack("h", np.imag(c)*short)
    return re+im

# i first, q second
def complex_to_ishort_multi(floats, endian=""):
    rr = np.real(floats)
    ii = np.imag(floats)
    zz = np.array((rr,ii)).transpose()
    zzz = zz.reshape(len(floats)*2) * (2**15-1)
    bytes = struct.pack(endian+"%sh" % len(zzz), *zzz)
    return bytes

# q first, i second
def complex_to_ishort_multi_rev(floats, endian=""):
    rr = np.real(floats)
    ii = np.imag(floats)
    zz = np.array((ii,rr)).transpose()
    zzz = zz.reshape(len(floats)*2) * (2**15-1)
    bytes = struct.pack(endian+"%sh" % len(zzz), *zzz)
    return bytes

# i first, q second
def ishort_to_complex_multi(ishort_bytes, endian=""):
    packed = struct.unpack(endian+"%dh" % int(len(ishort_bytes)/2), ishort_bytes)
    rere = sig_everyn(packed, 2, 0)
    imim = sig_everyn(packed, 2, 1)
    floats_recovered = list(itertools.imap(np.complex, rere, imim))
    return floats_recovered

# q first, i second
def ishort_to_complex_multi_rev(ishort_bytes, endian=""):
    packed = struct.unpack(endian+"%dh" % int(len(ishort_bytes)/2), ishort_bytes)
    rere = sig_everyn(packed, 2, 1)
    imim = sig_everyn(packed, 2, 0)
    floats_recovered = list(itertools.imap(np.complex, rere, imim))
    return floats_recovered

def complex_to_raw_multi(floats, endian=""):
    rr = np.real(floats)
    ii = np.imag(floats)
    zz = np.array((rr,ii)).transpose()
    zzz = zz.reshape(len(floats)*2)
    bytes = struct.pack(endian+"%sf" % len(zzz), *zzz)
    return bytes

def raw_to_complex_multi(raw_bytes):
    packed = struct.unpack("%df" % int(len(raw_bytes)/4), raw_bytes)
    rere = sig_everyn(packed, 2, 0)
    imim = sig_everyn(packed, 2, 1)
    floats_recovered = list(itertools.imap(np.complex, rere, imim))
    return floats_recovered

# a pretty-print for hex strings
def get_rose(data):
    try:
        ret = ' '.join("{:02x}".format(ord(c)) for c in data)
    except TypeError, e:
        ret = str(data)
    return ret

def print_rose(data):
    print get_rose(data)

def get_rose_int(data):
    # adding int values
    try:
        ret = ' '.join("{:02}".format(ord(c)) for c in data)
    except TypeError, e:
        ret = str(data)
    return ret

# if you want to go from the pretty print version back to a string (this would not be used in production)
def reverse_rose(input):
    orig2 = ''.join(input.split(' '))
    orig = str(bytearray.fromhex(orig2))
    return orig

# this is meant to replace print comma like functionality for ben being lazy
def s_(*args):
    out = ''
    for arg in args:
        out += str(arg)+' '
    out = out[:-1]
    return out

def print_hex(str, ascii = False):
    print 'hex:'
    tag = ''
    for b in str:
        if ascii:
            if b in string.printable:
                tag = b
            else:
                tag = '?'
        print ' ', format(ord(b), '02x'), tag

def print_dec(str):
    print 'hex:'
    for b in str:
        print ' ', ord(b)

# http://stackoverflow.com/questions/10237926/convert-string-to-list-of-bits-and-viceversa
def str_to_bits(s):
    result = []
    for c in s:
        bits = bin(ord(c))[2:]
        bits = '00000000'[len(bits):] + bits
        result.extend([int(b) for b in bits])
    return result

def bits_to_str(bits):
    chars = []
    for b in range(len(bits) / 8):
        byte = bits[b*8:(b+1)*8]
        chars.append(chr(int(''.join([str(bit) for bit in byte]), 2)))
    return ''.join(chars)

def all_to_ascii(data):
    if isinstance(data, basestring):
        return str(data)
    elif isinstance(data, collections.Mapping):
        return dict(map(all_to_ascii, data.iteritems()))
    elif isinstance(data, collections.Iterable):
        return type(data)(map(all_to_ascii, data))
    else:
        return data

def floats_to_bytes(rf):
    return ''.join([complex_to_ishort(x) for x in rf])

def bytes_to_floats(rxbytes):
    packed = struct.unpack("%dh" % int(len(rxbytes)/2), rxbytes)
    rere = sig_everyn(packed, 2, 0)
    imim = sig_everyn(packed, 2, 1)
    assert len(rere) == len(imim)
    rx = list(itertools.imap(np.complex, rere, imim))

def drange(start, end=None, inc=None):
    """A range function, that does accept float increments..."""
    import math

    if end == None:
        end = start + 0.0
        start = 0.0
    else: start += 0.0 # force it to be a float

    if inc == None:
        inc = 1.0
    count = int(math.ceil((end - start) / inc))

    L = [None,] * count

    L[0] = start
    for i in xrange(1,count):
        L[i] = L[i-1] + inc
    return L

def unroll_angle(input):
    thresh = np.pi

    adjust = 0

    sz = len(input)

    output = [None]*sz

    output[0] = input[0]

    for index in range(1,sz):
        samp = input[index]
        prev = input[index-1]

        if(abs(samp-prev) > thresh):
            direction = 1
            if( samp > prev ):
                direction = -1
            adjust = adjust + 2*np.pi*direction

        output[index] = input[index] + adjust

    return output

def bits_cpm_range(bits):
    bits = [(b*2)-1 for b in bits] # convert to -1,1
    return bits

def bits_binary_range(bits):
    bits = [int((b+1)/2) for b in bits]  # convert to ints with range of 0,1
    return bits

def ip_to_str(address):
    return socket.inet_ntop(socket.AF_INET, address)

def nonblock_read(sock, size):
    try:
        buf = sock.read()
    except IOError, e:
        err = e.args[0]
        if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
            return None  # No data available
        else:
            # a "real" error occurred
            print e
            sys.exit(1)
    else:
        if len(buf) == 0:
            return None
        return buf

# returns None if socket doesn't have any data, otherwise returns a list of bytes
# you need to set os.O_NONBLOCK on the socket at creation in order for this function to work
#   fcntl.fcntl(sock, fcntl.F_SETFL, os.O_NONBLOCK)
def nonblock_socket(sock, size):
    # this try block is the non blocking way to grab UDP bytes
    try:
        buf = sock.recv(size)
    except socket.error, e:
        err = e.args[0]
        if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
            return None  # No data available
        else:
            # a "real" error occurred
            print e
            sys.exit(1)
    else:
        # got data
        return buf

def nonblock_socket_from(sock, size):
    # this try block is the non blocking way to grab UDP bytes
    try:
        buf, addr = sock.recvfrom(size)
    except socket.error, e:
        err = e.args[0]
        if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
            return None, None  # No data available
        else:
            # a "real" error occurred
            print e
            sys.exit(1)
    else:
        # got data
        return buf, addr

def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in xrange(0, len(l), n):
        yield l[i:i+n]

def save_rf_grc(filename, data):
    dumpfile = open(filename, 'w')
    for s in data:
        dumpfile.write(complex_to_raw(s))
    dumpfile.close()

def read_rf_grc(filename, max_samples=None):
    file = open(filename, 'r')
    piece_size = 8
    dout = []
    sample_count = 0
    while True:
        bytes = file.read(piece_size)

        if bytes == "":
            break  # end of file
        dout.append(raw_to_complex(bytes))
        sample_count += 1
        if max_samples is not None and sample_count >= max_samples:
            break

    return dout

# write rf to a csv file
# to read file from matlab
# k = csvread('Y:\home\ubuntu\python-osi\qam4.csv');
# kc = k(:,1) + k(:,2)*1j;
def save_rf(filename, data):
    dumpfile = open(filename, 'w')
    for s in data:
        print >> dumpfile, np.real(s), ',', np.imag(s)
    dumpfile.close()

# read rf from a csv file
# if your file is dc in matlab, run this:
#   dcs = [real(dc) imag(dc)];
#   csvwrite('filename.csv',dcs);
#   csvwrite('h3packetshift.csv', [real(dc) imag(dc)]);
def read_rf(filename):
    # read a CSV file
    file = open(filename, 'r')
    reader = csv.reader(file, delimiter=',', quotechar='|')
    data = []
    for row in reader:
        data.append(float(row[0]) + float(row[1])*1j)
    file.close()
    return data

def read_rf_hack(filename):
    # read a CSV file
    file = open(filename, 'r')
    reader = csv.reader(file, delimiter=',', quotechar='|')
    data = []
    for row in reader:
        data.append(float(row[0]))
        data.append(float(row[1]))
    file.close()
    return data

# basic logging setup
def setup_logger(that, name, prefix=None):
    if prefix is None:
        prefix = name

    that.log = logging.getLogger(name)
    that.log.setLevel(logging.INFO)
    # create console handler and set level to debug
    lch = logging.StreamHandler()
    lch.setLevel(logging.INFO)
    lfmt = logging.Formatter(prefix+': %(message)s')
    # add formatter to channel
    lch.setFormatter(lfmt)
    # add ch to logger
    that.log.addHandler(lch)

# convert a list of bits to an unsigned int
# h is the number of bits we are expecting in the list
def bit_list_unsigned_int(lin, h):
    sym = 0
    for j in range(h):
        try:
            sym += lin[j]*2**(h-j-1)
        except IndexError:
            sym += 0
    return sym

def find_nearest(array,value):
    idx = (np.abs(array-value)).argmin()
    return (idx,array[idx])

def tone_gen(samples, fs, hz):
    assert type(samples) == type(0)
    assert type(fs) in (int, long)

    inc = 1.0/fs * 2 * np.pi * hz

    if hz == 0:
        args = np.array([0] * samples)
    else:
        args = np.linspace(0, (samples-1) * inc, samples) * np.array([1j] * samples)
    return np.exp(args)

## pass in raw rf data first, and your ideal search wave second
# pass show to nplot the result
# pass everything to return all data, defaults to false
def typical_xcorr(data, search, show=False,everything=False):
    xcr = np.correlate(data, search, 'full')
    absxcr = abs(xcr)  # save absolute value
    xcrscore, xcridx = sig_max(absxcr) # find the max of the abs (score), and the index of that
    peakxcr = xcr[xcridx]  # apply the index to the non abs xcr, to get a sample we can take the angle of
    sampleangle = np.angle(peakxcr)

    if show:
        nplot(absxcr, "abs of xcorr output")

    if everything:
        return xcridx, peakxcr, sampleangle, xcrscore, xcr
    else:
        return xcridx, peakxcr, sampleangle
    #fixme, get lags out

def mat_nicename(H):
    return "Matrix (h,w) %d %d"%(H.shape[0],H.shape[1])

# inplace modifies H
def mat_switch_rows(H, ida, idb):
    t = np.copy(H[ida,:])
    H[ida,:] = H[idb,:]
    H[idb,:] = t
    return None

# inplace
def mat_switch_cols(H, ida, idb):
    t = np.copy(H[:,ida])
    H[:,ida] = H[:,idb]
    H[:,idb] = t
    return None

def o_map_psk(din):

    res = []

    pairwise = zip(din[::2], din[1::2])

    for cut in pairwise:
        if cut == (0,0):
            res.append(2)
        elif cut == (0,1):
            res.append(1)
        elif cut == (1,0):
            res.append(3)
        elif cut == (1,1):
            res.append(0)

    return res

# Returns baked output from the matlab command:
#  rrcFilter = rcosdesign(rolloff, span, sps);
# if a new set of params is passed, this returns None
def o_rrc_filter_lookup(rolloff, span, sps):
    rrcFilter = None

    if rolloff == 0.25 and span == 6 and sps == 4:
        rrcFilter = [-0.0187733440045221, 0.003013558666422, 0.0326772345462546, 0.0470935833402524, 0.0265495177022908, -0.0275222240300177, -0.0852248750170832, -0.0994474359919262, -0.0321472673983147, 0.119037148179254, 0.311176411555479, 0.472003895565433, 0.534632070178156, 0.472003895565433, 0.311176411555479, 0.119037148179254, -0.0321472673983147, -0.0994474359919262, -0.0852248750170832, -0.0275222240300177, 0.0265495177022908, 0.0470935833402524, 0.0326772345462546, 0.003013558666422, -0.0187733440045221]
    elif rolloff == 0.25 and span == 8 and sps == 6:
        rrcFilter = [0.00866532792410113, 0.00658252680452728, 0.000689062625426406, -0.0074712343335428, -0.0149894394106519, -0.0184751723085405, -0.0153182803408426, -0.00491214847998965, 0.0106347206341242, 0.0266632859560034, 0.0371116854587008, 0.0364198115321213, 0.0216633198102528, -0.00577076737254631, -0.0396028976063981, -0.069540009878394, -0.083558519268118, -0.0710847620356398, -0.0262308544541024, 0.0498600699425154, 0.148327139837451, 0.253907215811741, 0.348041615194585, 0.413040313779774, 0.436237887518672, 0.413040313779774, 0.348041615194585, 0.253907215811741, 0.148327139837451, 0.0498600699425154, -0.0262308544541024, -0.0710847620356398, -0.083558519268118, -0.069540009878394, -0.0396028976063981, -0.00577076737254631, 0.0216633198102528, 0.0364198115321213, 0.0371116854587008, 0.0266632859560034, 0.0106347206341242, -0.00491214847998965, -0.0153182803408426, -0.0184751723085405, -0.0149894394106519, -0.0074712343335428, 0.000689062625426406, 0.00658252680452728, 0.00866532792410113]
    elif rolloff == 0.25 and span == 10 and sps == 8:
        rrcFilter =  [-0.00265291895695268, -0.0038367285758387, -0.00404178046649392, -0.00307918477864112, -0.00103711397846142, 0.00170441339943213, 0.0045271711482077, 0.00669247991307441, 0.00750358793759834, 0.00648076379403586, 0.00351054324124175, -0.00106825247595824, -0.00646958364590197, -0.0115675402132076, -0.0150962227680158, -0.0159112035315436, -0.0132645947847634, -0.0070368939631878, 0.0021292761993053, 0.0128349930785245, 0.0230886023735744, 0.0306157954214996, 0.0332746952178824, 0.0295092014286344, 0.0187589698439958, 0.00174365601293929, -0.0194462504520092, -0.0414910755739182, -0.0602169454952409, -0.0711634708322952, -0.0702661145770751, -0.0545489915088333, -0.0227141459386971, 0.0244771507857901, 0.0841075268503736, 0.151324993567835, 0.219866476897559, 0.282817489474821, 0.333501607917967, 0.366369319357036, 0.37775250739262, 0.366369319357036, 0.333501607917967, 0.282817489474821, 0.219866476897559, 0.151324993567835, 0.0841075268503736, 0.0244771507857901, -0.0227141459386971, -0.0545489915088333, -0.0702661145770751, -0.0711634708322952, -0.0602169454952409, -0.0414910755739182, -0.0194462504520092, 0.00174365601293929, 0.0187589698439958, 0.0295092014286344, 0.0332746952178824, 0.0306157954214996, 0.0230886023735744, 0.0128349930785245, 0.0021292761993053, -0.0070368939631878, -0.0132645947847634, -0.0159112035315436, -0.0150962227680158, -0.0115675402132076, -0.00646958364590197, -0.00106825247595824, 0.00351054324124175, 0.00648076379403586, 0.00750358793759834, 0.00669247991307441, 0.0045271711482077, 0.00170441339943213, -0.00103711397846142, -0.00307918477864112, -0.00404178046649392, -0.0038367285758387, -0.00265291895695268]
    elif rolloff == 0.5 and span == 10 and sps == 8:
        rrcFilter = [-0.000227360782730039200000,0.001088738429480835300000,0.002084746204746209700000,0.002371375200663914500000,0.001768451863687256400000,0.000392002682105138340000,-0.001351170708598336100000,-0.002870096591219498600000,-0.003572812300043569700000,-0.003072796427970129000000,-0.001351170708598331300000,0.001186149711456712000000,0.003789539707901269900000,0.005576181317467936900000,0.005816879270585570100000,0.004213430128940225500000,0.001071843690013067400000,-0.002702793301169967200000,-0.005816879270585570900000,-0.006968996504726427200000,-0.005305355591061771000000,-0.000815566309429241660000,0.005469024296707546000000,0.011574239347020513000000,0.015005811660182994000000,0.013431057725172559000000,0.005469024296707539000000,-0.008615925345214449000000,-0.026526777955308903000000,-0.044010343226686024000000,-0.055454249046249099000000,-0.054933726077336487000000,-0.037514529150457464000000,-0.000532406049215232180000,0.055454249046249134000000,0.126292748642899940000000,0.204584829987635860000000,0.280739008412446870000000,0.344548530692574790000000,0.386989294703540040000000,0.401870228675680950000000,0.386989294703540040000000,0.344548530692574790000000,0.280739008412446870000000,0.204584829987635860000000,0.126292748642899940000000,0.055454249046249134000000,-0.000532406049215232180000,-0.037514529150457464000000,-0.054933726077336487000000,-0.055454249046249099000000,-0.044010343226686024000000,-0.026526777955308903000000,-0.008615925345214449000000,0.005469024296707539000000,0.013431057725172559000000,0.015005811660182994000000,0.011574239347020513000000,0.005469024296707546000000,-0.000815566309429241660000,-0.005305355591061771000000,-0.006968996504726427200000,-0.005816879270585570900000,-0.002702793301169967200000,0.001071843690013067400000,0.004213430128940225500000,0.005816879270585570100000,0.005576181317467936900000,0.003789539707901269900000,0.001186149711456712000000,-0.001351170708598331300000,-0.003072796427970129000000,-0.003572812300043569700000,-0.002870096591219498600000,-0.001351170708598336100000,0.000392002682105138340000,0.001768451863687256400000,0.002371375200663914500000,0.002084746204746209700000,0.001088738429480835300000,-0.000227360782730039200000]

    return rrcFilter

# pass in any sparse, this will convert to bsr sparse and save
def fancy_save_sparse(filename, H):
    Hsparse = scipy.sparse.bsr_matrix(H, dtype=np.int16)
    save_sparse_csr(filename, Hsparse)

# def fancy_load_sparse(filename):
#     loader = np.load(filename)
#     bsr = scipy.sparse.bsr_matrix((  loader['data'], loader['indices'], loader['indptr']), shape = loader['shape'])

# only pass type of bsr
def save_sparse_csr(filename, array):
    assert type(array) == scipy.sparse.bsr.bsr_matrix
    np.savez(filename, data=array.data, indices=array.indices, indptr=array.indptr, shape=array.shape )

def load_sparse_csr(filename):
    loader = np.load(filename)
    return scipy.sparse.bsr_matrix((  loader['data'], loader['indices'], loader['indptr']), shape = loader['shape'])

def runningMean(x, N):
    y = np.zeros((len(x),))
    for ctr in range(len(x)):
         y[ctr] = np.sum(x[ctr:(ctr+N)])
    return y/N

# ---------------- Beginning of matplotlib
##
# @defgroup nplot Plotting related helper functions
# @{
#

_nplot_figure = 0

##
#  Plot the sparsity pattern of 2-D array
# @param A the 2-D array
# @param title The plot title (string)
def nplotspy(A, title=""):
    fig = nplotfigure()

    plt.title(title)
    plt.spy(A, precision=0.01, markersize=3)

    return fig

def ncplot(rf, title=None, newfig=True):
    fig = None

    if newfig:
        fig = nplotfigure()

    if title is not None:
        plt.title(title)

    plt.plot(np.real(rf))
    plt.plot(np.imag(rf), 'r')
    return fig

def nplot(rf, title=None, newfig=True):
    fig = None

    if newfig:
        fig = nplotfigure()

    if title is not None:
        plt.title(title)

    plt.plot(np.real(rf))
    return fig

def nplotdots(rf, title="", hold=False):
    fig = None
    if hold:
        plt.hold(True)
    else:
        fig = nplotfigure()
        plt.title(title)
    plt.plot(range(len(rf)), np.real(rf), '-ko')
    return fig

def nplotqam(rf, title="", newfig=True):
    fig = None

    if newfig:
        fig = nplotfigure()

    if title is not None:
        plt.title(title)

    plt.plot(np.real(rf), np.imag(rf), '.b', alpha=0.6)
    return fig

def nplotfftold(rf, title="", hold=False):
    fig = None

    if hold:
        plt.hold(True)
    else:
        fig = nplotfigure()
        plt.title(title)

    plt.plot(abs(fftshift(fft(rf))))
    return fig

def sig_peaks(bins, hz, num = 1, peaksHzSeparation = 1):
    binsabs = np.abs(bins)

    llen = len(bins)

    # approx method, assumes all bins are evenly spaces (they better be)
    binstep = hz[1] - hz[0]
    hzsepinbins = np.ceil(peaksHzSeparation / binstep)

    res = []

    for i in range(num):
        maxval,peakidx = sig_max(binsabs)
        res.append(peakidx)

        lowbin = int(np.max([0,peakidx-hzsepinbins]))
        highbin = int(np.min([llen,peakidx+hzsepinbins]))

        binsabs[lowbin:highbin] = 0.

    return res

def nplotfft(rf, fs = 1, title=None, newfig=True, peaks=False, peaksHzSeparation=1, peaksFloat=1.1):
    fig = None

    if newfig is True:
        fig = nplotfigure()

    if title is not None:
        plt.title(title)

    N = len(rf)

    X = fftshift(fft(rf)/N)
    absbins = 2*np.abs(X)
    df = fs/N
    f = np.linspace(-fs/2, fs/2-df, N)

    plt.plot(f, absbins)
    plt.xlabel('Frequency (in hertz)')
    plt.ylabel('Magnitude Response')

    if peaks:
        peaksres = sig_peaks(X, f, peaks, peaksHzSeparation)
        if type(newfig) is type(True):
            ax = fig.add_subplot(111)
        else:
            ax = newfig

        for pk in peaksres:

            maxidx = pk
            maxval = absbins[pk]

            lbl = s_('hz:', f[maxidx])

            ax.annotate(lbl, xy=(f[maxidx], maxval), xytext=(f[maxidx], maxval * peaksFloat),
                        arrowprops=dict(facecolor='black'),
                        )

    return fig

def nplothist(x, title = "", bins = False):
    fig = nplotfigure()

    plt.title(title)

    # more options
    # n, bins, patches = plt.hist(x, 50, normed=1, facecolor='green', alpha=0.75)

    if bins is not False:
        plt.hist(x, bins)
    else:
        plt.hist(x)

    # plt.xlabel('x')
    # plt.ylabel('y')
    # plt.axis([40, 160, 0, 0.03])
    plt.grid(True)
    return fig

def nplotber(bers, ebn0, titles, title = ""):
    assert(len(bers) == len(ebn0) == len(titles))

    fig = nplotfigure()

    maintitle = "BER of ("

    for i in range(len(bers)):
        # check if any values are positive
        if any(k > 0 for k in bers[i]):
            # if so plot normally
            plt.semilogy(ebn0[i], bers[i], '-s', linewidth=2)
            maintitle += titles[i] + ', '
        else:
            # if all values are zero, don't plot (doing so forever prevents this plot window from drawing new lines)
            maintitle += 'ValueError: Data has no positive values, and therefore can not be log-scaled.' + ', '

    maintitle += ")"

    gridcolor = '#B0B0B0'
    plt.grid(b=True, which='major', color=gridcolor, linestyle='-')
    plt.grid(b=True, which='minor', color=gridcolor, linestyle='dotted')

    plt.legend(titles)
    plt.xlabel('Eb/No (dB)')
    plt.ylabel('BER')

    if title == "":
        plt.title(maintitle)
    else:
        plt.title(title)

    return fig

def nplotmulti(xVals, yVals, legends, xLabel ='x', yLabel ='y', title ='', semilog = False, newfig=True, style='-s'):
    assert(len(yVals) == len(xVals) == len(legends))

    fig = None
    if newfig:
        fig = nplotfigure()
        plt.title(title)

    for i in range(len(yVals)):
        if semilog == True:
            plt.semilogy(xVals[i], yVals[i], style, linewidth=2)
        elif semilog == False:
            plt.plot(xVals[i], yVals[i], style, linewidth=2)

    gridcolor = '#B0B0B0'
    plt.grid(b=True, which='major', color=gridcolor, linestyle='-')
    plt.grid(b=True, which='minor', color=gridcolor, linestyle='dotted')

    plt.legend(legends)
    plt.xlabel(xLabel)
    plt.ylabel(yLabel)

    return fig

def nplotangle(angle, title = None, newfig=True):
    global _nplot_figure
    fig = None
    if newfig:
        fig = plt.figure(_nplot_figure, figsize=(7.,6.))
        _nplot_figure += 1

    res = 100
    cir = np.exp(1j*np.array(range(res+1))/(res/np.pi/2))
    cir = np.concatenate(([0],cir))

    cir = cir * np.exp(1j*angle)

    plt.plot(np.real(cir), np.imag(cir), 'b', alpha=0.6, linewidth=3.0)
    if title is not None:
        plt.title(title)
    else:
        plt.title(s_("angle:", angle))
    return fig

def nplotshow():
    plt.show()

def nplotfigure():
    global _nplot_figure

    fig = plt.figure(_nplot_figure)
    _nplot_figure += 1

    return fig

def nplotresponselinear(b, a, cutoff, fs):
    w, h = scipy.signal.freqz(b, a, worN=8000)
    nplotfigure()
    plt.plot(0.5 * fs * w / np.pi, np.abs(h), 'b')
    plt.plot(cutoff, 0.5 * np.sqrt(2), 'ko')
    plt.axvline(cutoff, color='k')
    plt.xlim(0, 0.5 * fs)
    plt.title("Linear Lowpass Filter Frequency Response")
    plt.xlabel('Frequency [Hz]')
    plt.grid()

## Plots frequency response of digital filter
# @param b b coefficients
# @param a a coefficients
# @param mode set mode 'frequency' and also pass in fs to display units in hz, or set mode 'radians'
# @param title graph title
# @param fs fs of filter in 'frequency' mode
# @param cutoff draw a vertial line at the filters cutoff if you know it
def nplotresponse(b, a, mode='frequency', title='', fs=0, cutoff=None):
    w, h = scipy.signal.freqz(b, a)

    fig = nplotfigure()
    plt.title(title)
    ax1 = fig.add_subplot(111)

    if mode == 'frequency':
        wplot = 0.5 * fs * w / np.pi
        xlab = 'Frequency [Hz]'
    elif mode == 'radians':
        wplot = w
        xlab = 'Frequency [rad/sample]'
    else:
        assert 0

    plt.plot(wplot, 20 * np.log10(abs(h)), 'b')
    plt.ylabel('Amplitude [dB]', color='b')
    plt.xlabel(xlab)
    ax2 = ax1.twinx()
    angles = np.unwrap(np.angle(h))
    plt.plot(wplot, angles, 'g')
    plt.ylabel('Angle (radians)', color='g')
    plt.grid()
    plt.axis('tight')

    if cutoff is not None:
        plt.axvline(cutoff, color='k')

    return fig

def nplottext(str, newfig=True):
    fig = None
    if newfig == True:
        fig = nplotfigure()
        plt.title('txt')
        ax = fig.add_subplot(111)
    else:
        ax = newfig

    ax.set_aspect(1)

    bbox_props = dict(boxstyle="round", fc="w", ec="0.5", alpha=0.9)
    ax.text(0, 0, str, ha="center", va="center", size=14,
            bbox=bbox_props)
    ax.set_xlim(-4, 4)
    ax.set_ylim(-4, 4)

    return fig

##
# @}
#

def rand_string_ascii(len):
    return ''.join(random.choice(string.ascii_letters) for _ in range(len))

def sigflatten(listOfLists):
    "Flatten one level of nesting"
    return chain.from_iterable(listOfLists)

def sigdup(listt, count=2):
    # return list(flatten([y for y in repeat([y for y in listt], count)]))
    return list(sigflatten([repeat(x, count) for x in listt]))

## wrapper around numpy's built in FFT that returns frequency of each bin
# note that this function returns data that has already been fftshift'd
# @param data data to fft
# @param fs samples per second to be used for bin calculation
# @returns (fft_data, bins)
def sig_fft(data, fs):

    dt = 1 / fs     #                % seconds per sample
    N = len(data)
     # Fourier Transform:
    X = fftshift(fft(data)/N)
    # %% Frequency specifications:
    dF = float(fs) / N     #                % hertz
    # f = -Fs/2:dF:Fs/2-dF;#           % hertz
    bins = drange(-fs / 2, fs / 2, dF)

    return X, bins
    # %% Plot the spectrum:
    # figure;
    # plot(f,2*abs(X));
    # xlabel('Frequency (in hertz)');
    # title('Magnitude Response');
    # disp('Each bin is ');
    # disp(dF);

def sig_rms(x):
    return np.sqrt(np.mean(x * np.conj(x)))

# returns the FIRST occurrence of the maximum
# this is the fastest by FAR, but it requires that data be an ndarray
# behaves like matlab max() do not pass in complex values and assume that this works
def sig_max(data):
    idx = np.argmax(data)
    m = data[idx]
    return (m, idx)

def sig_max2(data):
    m = max(data)
    idx = [i for i, j in enumerate(data) if j == m]
    idx = idx[0]
    return (m, idx)

def sig_max3(data):
    m = max(data)
    idx = data.index(m)
    return (m, idx)

def sig_max4(data):
    m = max(data)
    idx = data.index(m)
    return (m, idx)

def sig_everyn(data, n, phase=0):
    l = len(data)
    assert phase < n, "Phase must be less than n"
    assert n <= l, "n must be less than or equal length of data"

    # subtract the phase from length, and then grab that many elements from the end of data
    # this is the same as removing 'phase' elements from the beginning
    if phase != 0:
        phaseapplied = data[-1*(l-phase):]

        # after applying phase, return every nth element from that
        return phaseapplied[::n]
    else:
        return data[::n]

# http://stackoverflow.com/questions/17904097/python-difference-between-two-strings/17904977#17904977

def sig_diff(a,b,max=False):
    at = time.time()
    count = 0
    # print('{} => {}'.format(a,b))
    for i,s in enumerate(difflib.ndiff(a, b)):
        if s[0]==' ': continue
        elif s[0]=='-':
            try:
                c = u'{}'.format(s[-1])
            except:
                c = ' '
            print(u'Delete "{}" from position {}'.format(c,i))
        elif s[0]=='+':
            print(u'Add "{}" to position {}'.format(s[-1],i))
        count += 1
        if max and count >= max:
            print "stopping after", count, "differences"
            break
    print()
    bt = time.time()
    print "sig_diff() ran in ", bt-at

def sig_diff2(a, b, unused=False):
    lmin = min(len(a),len(b))
    lmax = max(len(a),len(b))

    errors = 0
    for i in range(lmin):
        if a[i] != b[i]:
            errors += 1

    errors += lmax-lmin
    if lmax != lmin:
        print "Strings were", errors, "different with additional", lmax-lmin, "due to length differences"
    else:
        print "Strings were", errors, "different"

# builds a ring of evenly spaced points, used for circular QAM
def buildQAMRing(r, count, rot=0):
        ainc = 1.0/count * 2 * np.pi

        points = [0] * count

        for i in range(count):
            p = np.e ** (1j * (rot + ainc*i))
            p *= r  # scale to amplitude for the ring
            points[i] = p
        return points

# returns the closest distance between a list of complex points
# used for checking the quality of QAM constellations
def listClosestDistance(points, verbose=True):

        best = 999999
        closestpair = (-1,-1)

        for i in range(len(points)):
            pouter = points[i]
            for k in range(len(points)):
                if i == k:
                    continue
                pinner = points[k]
                diff = min(best, abs(pouter-pinner))
                if diff < best:
                    best = diff
                    closestpair = (pouter,pinner)
        if verbose:
            print "closest", best, closestpair

        return (best,closestpair)

def sig_awgn(data, snrdb):
    ll = len(data)

    # only way I know to make complex noise
    noise = np.random.normal(0, 1, ll) + 0j
    rot = np.random.random_sample(ll)
    for i in range(len(noise)):
        noise[i] = noise[i] * np.exp(1j*rot[i]*2.0*np.pi) # random rotation with same amplitude

    sigma2 = 10.0**(-snrdb/10.0)
    out = data + noise*math.sqrt(sigma2)

    return out

## When using lower triangular matrices, this function will return the correct index for the relationship between any to indices
# (aka mirrors an upper triangular index to lower triangular index)
# @param a An index
# @param b An index
# @returns an index that is always lower triangular, as a tuple
def lower_triangular(a, b):
    if b > a:
        idx = (b, a)
    else:
        idx = (a, b)
    return idx

## Given N objects, returns unique pairs of objects
# Useful for upper/lower triangular matrices
# @param dim Number of objects
# @returns set() of tuples of unique objects
def unique_matrix_pair(dim, lt=False):
    s = set()
    for i in range(dim):
        for j in range(dim):
            if i != j:
                if (j, i) not in s:
                    if lt:
                        s.add(lower_triangular(i,j))
                    else:
                        s.add((i, j))
    return s

# accepts numpy matrices, always uses int16 math to compute sha
def sig_sha256_matrix(H):
    marshal = np.int16(H).tolist()
    return sig_sha256(marshal)

# converts the sparse matrix into dense, then returns the sha256
def sig_sha256_sparse_matrix(H):
    return sig_sha256_matrix(H.todense())

def sig_sha256(as_str):
    worker = hashlib.sha256()
    worker.update(str(as_str))
    return worker.digest()

def sig_lin_interp(a,b,ratio):
    # print "a", a
    # print "b", b
    # print "r", ratio
    slope = b-a
    return a+(slope*ratio)

def linear_unwrap(vec):
    llen = len(vec)
    std = -1
    idx = -1
    for i in range(llen):
        rolled = np.roll(vec, i)
        unwrap = np.unwrap(rolled)

        sstd = np.std(np.diff(unwrap))

        if std == -1:
            std = sstd
            idx = i
        elif sstd < std:
            std = sstd
            idx = i

    return (np.unwrap(np.roll(vec, idx)), idx)

def circle_shift_line(vec):
    llen = len(vec)
    mmin = -1
    minindex = -1
    for i in range(llen):
        vec_shift = np.roll(vec,i)
        s = np.std(np.diff(vec_shift))
        if minindex == -1:
            mmin = s
            minindex = i
        elif s < mmin:
            mmin = s
            minindex = i

    rolled = np.roll(vec, minindex)
    return (rolled,minindex)

def linear_zero_cross(vec):
    lhs = -1
    for i in range(len(vec)):
        sam = vec[i]
        if lhs == -1:
            if sam < 0:
                lhs = i - 1
                break
    rhs = lhs + 1
    lhss = vec[lhs]
    rhss = vec[rhs]
    slope = rhss - lhss

    zerocross = -lhss / slope + lhs
    return zerocross
        # print "lhs was", lhs
        # print "slope", slope
        # print "zerocross", zerocross

# circle shifts so that the peek is in the center, and the slope of the sides are always continuous
def circle_shift_peak(score_vec):
    llen = 8
    desired_centers = [3,4]
    assert len(score_vec) == llen, "circle_shift_peak only works for length 8 vectors"

    [maxval, maxidx] = sig_max(score_vec)
    beststd = 0
    bestidx = -1
    for desired in desired_centers:
        adj = desired - maxidx
        rolled = np.roll(score_vec, adj)
        title = s_('dataset', repr(score_vec)[0:5], ']  centered at', str(desired))

        # the set with the smaller std deviation of the double derivative is the one we want
        stddev = np.std(np.diff(np.diff(rolled)))

        if bestidx == -1:
            beststd = stddev
            bestidx = desired
        elif stddev < beststd:
            beststd = stddev
            bestidx = desired

    # txt = s_('dataset', repr(score_vec)[0:5], ']  best is ', bestidx)
    # print txt

    shift = bestidx-maxidx
    rolled = np.roll(score_vec, shift)

    # return a tuple with the shifted array and how much we did it by
    return (rolled, shift)

def sig_ms():
    import time
    millis = int(round(time.time() * 1000))
    return millis

## Pass samples of a peak
# Will polyfit, and then return maximum of fit curve
# @param peak's data samples, ususally I pass 8
# @param order order of polyfit, i use 4
# @param doplot pass True for very nice plot of what's going on
def polyfit_peak_climb(data, order, doplot = False):
    # http://stackoverflow.com/questions/29634217/get-minimum-points-of-numpy-poly1d-curve
    # https://docs.scipy.org/doc/numpy/reference/generated/numpy.polyfit.html

    # assume that interp os over 0-len(data)
    llen = len(data)
    x = range(llen)
    p = np.polyfit(x, data, order)
    pp = np.poly1d(p)  # create an object for easy lookups

    if doplot:
        # dont need to do costly linspace
        xp = np.linspace(x[0], x[-1], 100)
        nplotfigure()
        plt.plot(x, data, '.', xp, pp(xp))

    # this takes the deriv and idk exactly how it works
    crit = pp.deriv().r
    r_crit = crit[crit.imag == 0].real
    test = pp.deriv(2)(r_crit)
    x_max = r_crit[test < 0]

    if doplot:
        y_min = pp(x_max)
        plt.plot(x_max, y_min, 'o')
        xc = np.arange(0, 7, 0.02)
        yc = pp(xc)
        plt.plot(xc, yc)

    # with super high orders sometimes two maxima can be found
    # this attempts to remove any maxima that are outside the area of interest
    if len(x_max) > 1:
        # these two lines make bool arrays for the given conditions
        validleft = x_max >= 0
        validright = x_max <= llen
        valid = []
        for j in range(len(x_max)):
            if validleft[j] and validright[j]:
                valid.append(x_max[j])

        assert len(valid) == 1, "More than one maxima found in range of interest"
        x_max = valid

    # due to weirdness above, always unencapsulate off the only list element
    return x_max[0]

def fix_rad(rad):
    return math.fmod(rad, np.pi*2)
    # return rad % np.pi*2

def butter_lowpass(cutoff, fs, order):
    nyq = 0.5 * fs
    normal_cutoff = cutoff / nyq
    b, a = scipy.signal.butter(order, normal_cutoff, btype='low', analog=False)
    return b, a

def printOsiStack(stack):
    ptr = stack

    print "Bottom item is lowest:"

    lines = []

    while True:
        lines.append(s_('', ptr.name, type(ptr)))
        if not ptr.up:
            break
        ptr = ptr.up

    lines.reverse()

    for l in lines:
        print l

def osc_freq_drift(prev,time,Fc):
    f_delta_mean = time * -0.5e-9 / (2 * 3600) * Fc
    f_delta_variance = 0.2e-9 * Fc
    f_delta = f_delta_variance * (np.random.randn()) + f_delta_mean
    return prev+f_delta

def sigfdelayconvolution(signal, h):
    """ function that performs linear convolution """
    output = scipy.convolve(signal, h, "same")
    return output

## fractional delay
#
def sigfdelay(signal, N):
    assert N <= 1
    f = N
    i = 1

    # print "using f", f, "and i", i
    # print "using", [i - f, f]

    # perform linear interpolation for fractional delay
    output = sigfdelayconvolution(signal, [i - f, f])

    return output

def zero_insertion_upsample_complex(din, up):
    rem = up - 1
    llen = len(din)
    llenup = llen*up

    dout = [0.0j]*llenup
    dout[0::up] = din

    # This fn was built for upfirdn which does
    # zero inserion where the final zeros are excluded, ikd why but here goes
    return dout[:-rem]

def zero_insertion_upsample_real(din, up):
    # remainder, aka how many zeros between samples
    rem = up - 1

    # length of input
    llen = len(din)

    # length of output
    llenup = llen*up

    # magic indicing
    dout = [0.0]*llenup
    dout[0::up] = din

    # This fn was built for upfirdn which does
    # zero inserion where the final zeros are excluded, ikd why but here goes
    return dout[:-rem]

## dot.notation access to dictionary attributes
class ExposeDictionary(dict):
     __getattr__ = dict.get
     __setattr__ = dict.__setitem__
     __delattr__ = dict.__delitem__

from stackcall import StackCall
from continuousiir import ContinuousIIR

def sig_upfirn_real(data,filter,up,down):

    dup = zero_insertion_upsample_real(data, up)
    print "len dup", len(dup)

    filtero = StackCall(ContinuousIIR(filter, [1.0]))

    print "lengh of input plus length of filter minus 1", len(dup) + len(filter)-1

    extra = max(0,len(filter)-1)

    option = np.concatenate((np.array(dup),np.array([0]*extra)))

    output = filtero.rxup(option)

    return output

def sig_upfirdn_up_complex(data, filter, up):

    dup = zero_insertion_upsample_complex(data, up)
    # print "len dup", len(dup)

    filtero = StackCall(ContinuousIIR(filter, [1.0]))

    # print "lengh of input plus length of filter minus 1", len(dup) + len(filter)-1

    extra = max(0,len(filter)-1)

    option = np.concatenate((np.array(dup),np.array([0.0j]*extra)))

    output = filtero.rxup(option)

    return output

def sig_upfirdn_down_complex(data,filter,span,down):

    filtero = StackCall(ContinuousIIR(filter, [1.0]))

    output = filtero.rxup(data)

    ds = output[0::down]

    return ds[span:]

def polyphase_sequence(period=8, periods=1, q=1, s=1):
    ''' Generate a polyphase sequence (q, s, and period should be relatively prime) '''
    x = np.zeros(period*periods, dtype=np.complex)
    if period & 1 == 0:
        for p in range(periods):
            x[period*p:period*(p+1)] = np.exp(-q*1j*np.pi*np.arange(period)**2.0/(s * period))
    else:
        for p in range(periods):
            x[period*p:period*(p+1)] = np.exp(-q*1j*np.pi*np.arange(period)*np.arange(-1, period-1)/(s * period))
    return x

def root_cosine(N, L, alpha, apply_window=False):
    ''' Generate root raised cosine pulse shape '''
    if (N & 1) == 0:
        # Even length
        t = np.arange(-int(N/2), int(N/2)) / float(L) + 0.5 / float(L)
    else:
        # Odd length
        t = np.arange(-int((N-1)/2), int((N-1)/2+1)) / float(L)

    h = np.zeros_like(t)

    for k in range(N):
        if t[k] == 0:
            h[k] = 1.0 - alpha + 4.0 * alpha / np.pi
        elif abs(t[k]) == 1.0 / (4.0 * alpha):
            a0 = (1.0 + 2.0 / np.pi) * np.sin(np.pi / 4.0 / alpha)
            a1 = (1.0 - 2.0 / np.pi) * np.cos(np.pi / 4.0 / alpha)
            h[k] = alpha / np.sqrt(2.0) * (a0 + a1)
        else:
            a0 = np.sin(np.pi * (1.0 - alpha) * t[k])
            a1 = 4.0 * alpha * t[k] * np.cos(np.pi * (1.0 + alpha) * t[k])
            a2 = np.pi * t[k] * (1.0 - (16.0 * alpha * alpha * t[k] * t[k]))
            h[k] = (a0 + a1) / a2

    # Hamming Window
    if apply_window:
        h *= 0.54 - 0.46 * np.cos(2*np.pi*np.arange(0, N) / (N - 1))

    return h

## Returns the current line number in our program.
def lineno(up = 0):
    if up == 0:
        return inspect.currentframe().f_back.f_lineno
    if up == 1:
        return inspect.currentframe().f_back.f_back.f_lineno

def sigtest_requires_gui(some_function):
    def wrapper(*args, **kwargs):
        if os.environ.has_key("UNITTEST_NO_X11"):
            return
        some_function(*args, **kwargs)
    return wrapper

# these are using the same variable for now, but it makes it
# eaiser because tests specifically say what they require
def sigtest_requires_octave(some_function):
    def wrapper(*args, **kwargs):
        if os.environ.has_key("UNITTEST_NO_X11"):
            return
        some_function(*args, **kwargs)
    return wrapper

def sigtest_artik_will_skip(some_function):
    def wrapper(*args, **kwargs):
        if os.environ.has_key("UNITTEST_NO_X11"):
            return
        some_function(*args, **kwargs)
    return wrapper

if os.environ.has_key("UNITTEST_NO_X11"):
    def nplot_dummy(*args, **kwargs):
        pass

    nplotspy = nplot_dummy
    nplot = nplot_dummy
    nplotdots = nplot_dummy
    nplotqam = nplot_dummy
    nplotfftold = nplot_dummy
    nplotfft = nplot_dummy
    nplothist = nplot_dummy
    nplotber = nplot_dummy
    nplotmulti = nplot_dummy
    nplotangle = nplot_dummy
    nplotshow = nplot_dummy
    nplotfigure = nplot_dummy
    nplotresponselinear = nplot_dummy
    nplotresponse = nplot_dummy
    nplottext = nplot_dummy

max_stars_repo_name: esromneb/sigmath

max_issues_repo_name: esromneb/sigmath

max_forks_repo_name: esromneb/sigmath

reason: import numpy,from numpy,import scipy,from scipy


text:
from ...Functions.Load.import_class import import_class
from ...Classes._check import check_var
from numpy import ndarray, int32, int64, float32, float64

def _set_normalizations(self, value):
    """setter of normalizations"""
    if type(value) is dict:
        for key, obj in value.items():
            if type(obj) is dict:
                class_obj = import_class(
                    "SciDataTool.Classes", obj.get("__class__"), "normalizations"
                )
                value[key] = class_obj(init_dict=obj)
            elif isinstance(obj, (float, int, int32, int64, float32, float64)):
                Norm_ref = import_class(
                    "SciDataTool.Classes", "Norm_ref", "normalizations"
                )
                value[key] = Norm_ref(ref=obj)
            elif isinstance(obj, (ndarray, list)):
                Norm_vector = import_class(
                    "SciDataTool.Classes", "Norm_vector", "normalizations"
                )
                value[key] = Norm_vector(vector=obj)
    if type(value) is int and value == -1:
        value = dict()
    check_var("normalizations", value, "{Normalization}")
    self._normalizations = value

ext: py

reason: from numpy


text:
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np
import scipy.misc

def _to_range(images, min_value=0.0, max_value=1.0, dtype=None):
    # transform images from [-1.0, 1.0] to [min_value, max_value] of dtype
    assert \
        np.min(images) >= -1.0 - 1e-5 and np.max(images) <= 1.0 + 1e-5 \
        and (images.dtype == np.float32 or images.dtype == np.float64), \
        'The input images should be float64(32) and in the range of [-1.0, 1.0]!'
    if dtype is None:
        dtype = images.dtype
    return ((images + 1.) / 2. * (max_value - min_value) + min_value).astype(dtype)

def _im2uint(images):
    # transform images from [-1.0, 1.0] to uint8
    return _to_range(images, 0, 255, np.uint8)

def imread(path, mode='RGB'):
    """Read an image.

    read an image into [-1.0, 1.0] of float64

    `mode` can be one of the following strings:

    * 'L' (8 - bit pixels, black and white)
    * 'P' (8 - bit pixels, mapped to any other mode using a color palette)
    * 'RGB' (3x8 - bit pixels, true color)
    * 'RGBA' (4x8 - bit pixels, true color with transparency mask)
    * 'CMYK' (4x8 - bit pixels, color separation)
    * 'YCbCr' (3x8 - bit pixels, color video format)
    * 'I' (32 - bit signed integer pixels)
    * 'F' (32 - bit floating point pixels)
    """
    return scipy.misc.imread(path, mode=mode) / 127.5 - 1

def imwrite(image, path):
    # save an [-1.0, 1.0] image
    return scipy.misc.imsave(path, _to_range(image, 0, 255, np.uint8))

def imresize(image, size, interp='bilinear'):
    """Resize an image.

    Resize an [-1.0, 1.0] image.

    size: int, float or tuple
        * int - Percentage of current size.
        * float - Fraction of current size.
        * tuple - Size of the output image.

    interp: str, optional
        Interpolation to use for re - sizing('nearest', 'lanczos', 'bilinear', 'bicubic'
        or 'cubic').
    """
    # scipy.misc.imresize should deal with uint8 image, or it would cause some problem (scale the image to [0, 255])
    return (scipy.misc.imresize(_im2uint(image), size, interp=interp) / 127.5 - 1).astype(image.dtype)

def immerge(images, row, col):
    """Merge images.

    merge images into an image with (row * h) * (col * w)

    `images` is in shape of N * H * W(* C=1 or 3)
    """
    if images.ndim == 4:
        c = images.shape[3]
    elif images.ndim == 3:
        c = 1

    h, w = images.shape[1], images.shape[2]
    if c > 1:
        img = np.zeros((h * row, w * col, c))
    else:
        img = np.zeros((h * row, w * col))
    for idx, image in enumerate(images):
        i = idx % col
        j = idx // col
        img[j * h:j * h + h, i * w:i * w + w, ...] = image

    return img

reason: import numpy,import scipy


text:
import argparse
import rasterio
import numpy as np
from argparse import RawTextHelpFormatter
from progress.bar import IncrementalBar
from pyproj import CRS, Transformer
from struct import *
from PIL import Image

# Sanitize input using custom type
def downsample_type(x):
    x = int(x)
    if x < 1:
        raise argparse.ArgumentTypeError('Minimum downsampling option is 1')
    return x

# CLI SETUP
desc = 'Convert GeoTIFF raster data to rgba encoded PNG heightmaps'
parser = argparse.ArgumentParser(description=desc, formatter_class=RawTextHelpFormatter)
parser.add_argument('filepath', metavar='FILE', type=str,
                    help='file path for GeoTIFF (.tif) data')
parser.add_argument('-o', metavar='OUTFILE', type=str, default='heightmap.png',
                    help='specify output file/path (default: heightmap.png)')
parser.add_argument('-d', metavar='DOWNSAMPLE', default=1, type=downsample_type,
                    help='skip over every n-1 data points for smaller image output (default: 1)')
parser.add_argument('-v', metavar='VERTICAL SCALE', type=int, default=100,
                    help='height multiplier - controls vertical resolution (default=100)')
parser.add_argument('-n', '--normalize', action='store_true',
                    help='subtract min height from height values')
parser.add_argument('-p', '--project', action='store_true',
                    help='print detailed info about bounds in mercator projection')

# parse args
args = parser.parse_args()
scale = args.d
normalize = args.normalize
vertical_scale = args.v
project = args.project

# Inward offset for each edge
start_x = 0
start_y = 0
end_x = 0
end_y = 0

# Open and read dataset
dataset = rasterio.open(args.filepath)
width = dataset.width
height = dataset.height

topleft = dataset.transform * (0, 0)
botright = dataset.transform * (width, height)

width_in_meters = dataset.bounds.right - dataset.bounds.left
height_in_meters = dataset.bounds.top - dataset.bounds.bottom

image_width = (width - start_x - end_x) // scale
image_height = (height - start_y - end_y) // scale

print('Reading from', dataset.name, '\n')

print('Bounds:')
print('  ', dataset.crs)
print('  ', topleft)
print('  ', botright, '\n')

# Get mercator coordinates of bounds
if project:
    epsg = str(dataset.crs).split(':',1)[1]
    crs = CRS.from_epsg(int(epsg))

    proj = Transformer.from_crs(crs, crs.geodetic_crs)

    topleft_proj = proj.transform(topleft[0], topleft[1])
    botright_proj = proj.transform(botright[0], botright[1])

    print('   Mercator')
    print('  ', topleft_proj)
    print('  ', botright_proj, '\n')

print('Input Size:')
print('  Width: ', width, 'px (', width_in_meters, 'm)', sep='')
print('  Height: ', height, 'px (', height_in_meters, 'm)\n', sep='')

print('Output Size:')
print('  Width: ', image_width, 'px', sep='')
print('  Height: ', image_height, 'px\n', sep='')

# Extract elevation data
print('Rasterizing...')
band1 = dataset.read(1)
print('Done rasterizing\n')

# Get range of heights
minheight = float('inf')
maxheight = float('-inf')

# Scaled bounds of image sampling
min_sample_x = start_x // scale
max_sample_x = (width - end_x) // scale
min_sample_y = start_y // scale
max_sample_y = (height - end_y) // scale

# Track progress for large datasets
total_stripes = max_sample_x - min_sample_x

if normalize:
    bar = IncrementalBar('Calculating height extremes', max=total_stripes, suffix='%(percent)d%%')
    for x in range(min_sample_x, max_sample_x):
        for y in range(min_sample_y, max_sample_y):
            # Point to sample from raster data
            sample_x = x * scale
            sample_y = y * scale

            val = band1[sample_y][sample_x]
            if val < 0:
                continue

            if val < minheight:
                minheight = val
            elif val > maxheight:
                maxheight = val
        bar.next()
    bar.finish()
    print('Min height:', minheight, 'meters')
    print('Max height:', maxheight, 'meters\n')

# Drawing heightmap
heightmap = Image.new('RGBA', (image_width, image_height))

bar = IncrementalBar('Drawing heightmap', max=total_stripes, suffix='%(percent)d%%')
for x in range(min_sample_x, max_sample_x):
    for y in range(min_sample_y, max_sample_y):
        # Point to sample from raster data
        sample_x = x * scale
        sample_y = y * scale

        val = band1[sample_y][sample_x]

        if normalize:
            val -= minheight

        # Filter out missing data points
        if val < 0:
            val = 0

        val = int(val * vertical_scale)

        # Split 32-bit height value into tuple of four 8-bit values (rgba)
        rgba_bytes = pack('>I', val)
        rgba_vals = unpack('BBBB', rgba_bytes)
        heightmap.putpixel((x - min_sample_x, y - min_sample_y), rgba_vals)
    bar.next()
bar.finish()

print('Saving image...')
heightmap.save(args.o)

print('Done!')

reason: import numpy


text:
# Problem Set 3: Simulating the Spread of Disease and Virus Population Dynamics

import numpy
import random
import pylab

'''
Begin helper code
'''

class NoChildException(Exception):
    """
    NoChildException is raised by the reproduce() method in the SimpleVirus
    and ResistantVirus classes to indicate that a virus particle does not
    reproduce. You can use NoChildException as is, you do not need to
    modify/add any code.
    """

'''
End helper code
'''

#
# PROBLEM 2
#
class SimpleVirus(object):
    """
    Representation of a simple virus (does not model drug effects/resistance).
    """
    def __init__(self, maxBirthProb, clearProb):
        """
        Initialize a SimpleVirus instance, saves all parameters as attributes
        of the instance.
        maxBirthProb: Maximum reproduction probability (a float between 0-1)
        clearProb: Maximum clearance probability (a float between 0-1).
        """
        self.maxBirthProb = maxBirthProb
        self.clearProb = clearProb

    def getMaxBirthProb(self):
        """
        Returns the max birth probability.
        """
        return self.maxBirthProb

    def getClearProb(self):
        """
        Returns the clear probability.
        """
        return self.clearProb

    def doesClear(self):
        """ Stochastically determines whether this virus particle is cleared from the
        patient's body at a time step.
        returns: True with probability self.getClearProb and otherwise returns
        False.
        """
        return random.random() <= self.getClearProb()

    def reproduce(self, popDensity):
        """
        Stochastically determines whether this virus particle reproduces at a
        time step. Called by the update() method in the Patient and
        TreatedPatient classes. The virus particle reproduces with probability
        self.maxBirthProb * (1 - popDensity).

        If this virus particle reproduces, then reproduce() creates and returns
        the instance of the offspring SimpleVirus (which has the same
        maxBirthProb and clearProb values as its parent).

        popDensity: the population density (a float), defined as the current
        virus population divided by the maximum population.

        returns: a new instance of the SimpleVirus class representing the
        offspring of this virus particle. The child should have the same
        maxBirthProb and clearProb values as this virus. Raises a
        NoChildException if this virus particle does not reproduce.
        """
        reproduces = random.random() <= self.maxBirthProb * (1 - popDensity)
        if reproduces:
            return SimpleVirus(self.getMaxBirthProb(), self.getClearProb())
        else:
            raise NoChildException

class Patient(object):
    """
    Representation of a simplified patient. The patient does not take any drugs
    and his/her virus populations have no drug resistance.
    """

    def __init__(self, viruses, maxPop):
        """
        Initialization function, saves the viruses and maxPop parameters as
        attributes.

        viruses: the list representing the virus population (a list of
        SimpleVirus instances)

        maxPop: the maximum virus population for this patient (an integer)
        """
        self.viruses = viruses  # list of SimpleVirus() instances
        self.maxPop = maxPop    # integer

    def getViruses(self):
        """
        Returns the viruses in this Patient.
        """
        return self.viruses

    def getMaxPop(self):
        """
        Returns the max population.
        """
        return self.maxPop

    def getTotalPop(self):
        """
        Gets the size of the current total virus population.
        returns: The total virus population (an integer)
        """
        return len(self.viruses)

    def update(self):
        """
        Update the state of the virus population in this patient for a single
        time step. update() should execute the following steps in this order:

        - Determine whether each virus particle survives and updates the list
        of virus particles accordingly.

        - The current population density is calculated. This population density
          value is used until the next call to update()

        - Based on this value of population density, determine whether each
          virus particle should reproduce and add offspring virus particles to
          the list of viruses in this patient.

        returns: The total virus population at the end of the update (an
        integer)
        """
        self.viruses = [v for v in self.getViruses() if not v.doesClear()]
        popDensity = len(self.viruses) / float(self.maxPop)

        for v in self.viruses[:]: # cloned list
            try:
                self.viruses.append(v.reproduce(popDensity))
            except NoChildException:
                pass
        return self.getTotalPop()

#
# PROBLEM 3
#
def simulationWithoutDrug(numViruses, maxPop, maxBirthProb, clearProb,
                          numTrials):
    """
    Run the simulation and plot the graph for problem 3 (no drugs are used,
    viruses do not have any drug resistance).
    For each of numTrials trial, instantiates a patient, runs a simulation
    for 300 timesteps, and plots the average virus population size as a
    function of time.

    numViruses: number of SimpleVirus to create for patient (an integer)
    maxPop: maximum virus population for patient (an integer)
    maxBirthProb: Maximum reproduction probability (a float between 0-1)
    clearProb: Maximum clearance probability (a float between 0-1)
    numTrials: number of simulation runs to execute (an integer)

    Call simulationWithoutDrug(...) with the following parameters:
        -- numViruses = 100
        -- maxPop (maximum sustainable virus population) = 1000
        -- maxBirthProb (maximum reproduction probability for a virus particle) = 0.1
        -- clearProb (maximum clearance probability for a virus particle) = 0.05
    """
    trials = []
    timesteps = 300

    # run trials
    for __ in range(numTrials):
        populations = []
        # instantiate a Patient
        v = SimpleVirus(maxBirthProb, clearProb)
        viruses = [v for n in range(numViruses)]
        p = Patient(viruses, maxPop)
        # simulate virus clearance and reproduction
        for step in range(timesteps):
            populations.append(p.update())
        # add trial results
        trials.append(populations)

    # get averages per time step per trial
    step_averages = []
    for s in range(timesteps):
        this_step = []
        for t in trials:
            this_step.append(t[s])
        step_averages.append(sum(this_step) / float(numTrials))

    # plot results
    pylab.plot(step_averages, label='Total Virus Population Over Time')
    pylab.title('Simple Virus Reproduction Simulation')
    pylab.xlabel('Time Steps')
    pylab.ylabel('Average Virus Population')
    pylab.legend(loc='lower right')
    pylab.show()

#simulationWithoutDrug(100, 1000, 0.1, 0.05, 100)

#
# PROBLEM 4
#
class ResistantVirus(SimpleVirus):
    """
    Representation of a virus which can have drug resistance.
    """

    def __init__(self, maxBirthProb, clearProb, resistances, mutProb):
        """
        Initialize a ResistantVirus instance, saves all parameters as attributes
        of the instance.

        maxBirthProb: Maximum reproduction probability (a float between 0-1)

        clearProb: Maximum clearance probability (a float between 0-1).

        resistances: A dictionary of drug names (strings) mapping to the state
        of this virus particle's resistance (either True or False) to each drug.
        e.g. {'guttagonol':False, 'srinol':False}, means that this virus
        particle is resistant to neither guttagonol nor srinol.

        mutProb: Mutation probability for this virus particle (a float). This is
        the probability of the offspring acquiring or losing resistance to a drug.
        """
        SimpleVirus.__init__(self, maxBirthProb, clearProb)
        self.resistances = resistances
        self.mutProb = mutProb

    def getResistances(self):
        """
        Returns the resistances for this virus.
        """
        return self.resistances

    def getMutProb(self):
        """
        Returns the mutation probability for this virus.
        """
        return self.mutProb

    def isResistantTo(self, drug):
        """
        Get the state of this virus particle's resistance to a drug. This method
        is called by getResistPop() in TreatedPatient to determine how many virus
        particles have resistance to a drug.

        drug: The drug (a string)

        returns: True if this virus instance is resistant to the drug, False
        otherwise.
        """
        return self.resistances.get(drug, False)

    def reproduce(self, popDensity, activeDrugs):
        """
        Stochastically determines whether this virus particle reproduces at a
        time step. Called by the update() method in the TreatedPatient class.

        A virus particle will only reproduce if it is resistant to ALL the drugs
        in the activeDrugs list. For example, if there are 2 drugs in the
        activeDrugs list, and the virus particle is resistant to 1 or no drugs,
        then it will NOT reproduce.

        Hence, if the virus is resistant to all drugs
        in activeDrugs, then the virus reproduces with probability:

        self.maxBirthProb * (1 - popDensity).

        If this virus particle reproduces, then reproduce() creates and returns
        the instance of the offspring ResistantVirus (which has the same
        maxBirthProb, clearProb, and mutProb values as its parent).

        For each drug resistance trait of the virus (i.e. each key of
        self.resistances), the offspring has probability 1-mutProb of
        inheriting that resistance trait from the parent, and probability
        mutProb of switching that resistance trait in the offspring.

        For example, if a virus particle is resistant to guttagonol but not
        srinol, and self.mutProb is 0.1, then there is a 10% chance that
        that the offspring will lose resistance to guttagonol and a 90%
        chance that the offspring will be resistant to guttagonol.
        There is also a 10% chance that the offspring will gain resistance to
        srinol and a 90% chance that the offspring will not be resistant to
        srinol.

        popDensity: the population density (a float), defined as the current
        virus population divided by the maximum population

        activeDrugs: a list of the drug names acting on this virus particle
        (a list of strings).

        returns: a new instance of the ResistantVirus class representing the
        offspring of this virus particle. The child should have the same
        maxBirthProb and clearProb values as this virus. Raises a
        NoChildException if this virus particle does not reproduce.
        """
        resistant = True
        # check resistances
        for drug in activeDrugs:
            if not self.isResistantTo(drug):
                resistant = False
                break
        if resistant:
            reproduces = random.random() <= self.maxBirthProb * (1 - popDensity)
            if reproduces:
                # mutate resistances
                resistances = {k:v if random.random() > self.mutProb else
                               not v for k, v in self.resistances.items()}
                # return offspring
                return ResistantVirus(self.getMaxBirthProb(), self.getClearProb(),
                                      resistances, self.mutProb)
        raise NoChildException

class TreatedPatient(Patient):
    """
    Representation of a patient. The patient is able to take drugs and his/her
    virus population can acquire resistance to the drugs he/she takes.
    """

    def __init__(self, viruses, maxPop):
        """
        Initialization function, saves the viruses and maxPop parameters as
        attributes. Also initializes the list of drugs being administered
        (which should initially include no drugs).

        viruses: The list representing the virus population (a list of
        virus instances)

        maxPop: The  maximum virus population for this patient (an integer)
        """
        Patient.__init__(self, viruses, maxPop)
        self.prescriptions = []

    def addPrescription(self, newDrug):
        """
        Administer a drug to this patient. After a prescription is added, the
        drug acts on the virus population for all subsequent time steps. If the
        newDrug is already prescribed to this patient, the method has no effect.

        newDrug: The name of the drug to administer to the patient (a string).

        postcondition: The list of drugs being administered to a patient is updated
        """
        if newDrug not in self.prescriptions:
            self.prescriptions.append(newDrug)

    def getPrescriptions(self):
        """
        Returns the drugs that are being administered to this patient.

        returns: The list of drug names (strings) being administered to this
        patient.
        """
        return self.prescriptions

    def getResistPop(self, drugResist):
        """
        Get the population of virus particles resistant to the drugs listed in
        drugResist.

        drugResist: Which drug resistances to include in the population (a list
        of strings - e.g. ['guttagonol'] or ['guttagonol', 'srinol'])

        returns: The population of viruses (an integer) with resistances to all
        drugs in the drugResist list.
        """
        return len([v for v in self.viruses if all(v.isResistantTo(d) for d in drugResist)])

    def update(self):
        """
        Update the state of the virus population in this patient for a single
        time step. update() should execute these actions in order:

        - Determine whether each virus particle survives and update the list of
          virus particles accordingly

        - The current population density is calculated. This population density
          value is used until the next call to update().

        - Based on this value of population density, determine whether each
          virus particle should reproduce and add offspring virus particles to
          the list of viruses in this patient.
          The list of drugs being administered should be accounted for in the
          determination of whether each virus particle reproduces.

        - Reproduction probability:
          self.maxBirthProb * (1 - popDensity)

        returns: The total virus population at the end of the update (an
        integer)
        """
        # from Patient class:
        self.viruses = [v for v in self.getViruses() if not v.doesClear()]
        popDensity = len(self.viruses) / float(self.maxPop)

        for v in self.viruses[:]: # cloned list
            try:
                self.viruses.append(v.reproduce(popDensity, self.getPrescriptions())) # getPrescriptions only additional parameter
            except NoChildException:
                pass
        return self.getTotalPop()

#
# PROBLEM 5
#
def simulationWithDrug(numViruses, maxPop, maxBirthProb, clearProb, resistances,
                       mutProb, numTrials):
    """
    Runs simulations and plots graphs for problem 5.

    For each of numTrials trials, instantiates a patient, runs a simulation for
    150 timesteps, adds guttagonol, and runs the simulation for an additional
    150 timesteps.  At the end plots the average virus population size
    (for both the total virus population and the guttagonol-resistant virus
    population) as a function of time.

    numViruses: number of ResistantVirus to create for patient (an integer)
    maxPop: maximum virus population for patient (an integer)
    maxBirthProb: Maximum reproduction probability (a float between 0-1)
    clearProb: maximum clearance probability (a float between 0-1)
    resistances: a dictionary of drugs that each ResistantVirus is resistant to
                 (e.g., {'guttagonol': False})
    mutProb: mutation probability for each ResistantVirus particle
             (a float between 0-1).
    numTrials: number of simulation runs to execute (an integer)

    """
    timesteps = 300
    treatment = 150
    totTrialPops = [] # total populations
    resTrialPops = [] # resistant populations

    for __ in range(numTrials):
        totPop = []
        resPop = []
        # instantiate a TreatedPatient
        v = ResistantVirus(maxBirthProb, clearProb, resistances, mutProb)
        viruses = [v for n in range(numViruses)]
        p = TreatedPatient(viruses, maxPop)
        # simulate virus clearance and reproduction
        for step in range(timesteps):
            if step == treatment:
                # introduce a new prescription
                p.addPrescription(random.choice([r for r in resistances.keys()]))
            p.update()
            totPop.append(p.getTotalPop())
            resPop.append(p.getResistPop([r for r in resistances.keys()]))
        totTrialPops.append(totPop)
        resTrialPops.append(resPop)

    # get total population averages per time step per trial
    tot_averages = []
    for s in range(timesteps):
        this_step = []
        for t in totTrialPops:
            this_step.append(t[s])
        tot_averages.append(sum(this_step) / float(numTrials))

    # get resistant population averages per time step per trial
    res_averages = []
    for s in range(timesteps):
        this_step = []
        for t in resTrialPops:
            this_step.append(t[s])
        res_averages.append(sum(this_step) / float(numTrials))

    # plot results
    pylab.plot(tot_averages, label='Total Virus Pop.')
    pylab.plot(res_averages, label='Resistant Virus Pop.')
    pylab.title('Simulation of Resistant Virus in Treated Patient')
    pylab.xlabel('Time Steps')
    pylab.ylabel('Average Virus Population')
    pylab.legend(loc='upper right')
    pylab.show()

simulationWithDrug(100, 1000, 0.1, 0.05, {'guttagonol': False}, 0.005, 100)

max_stars_repo_name: batmanbury/edX

max_stars_repo_licenses: Xnet Linux-OpenIB X11

max_issues_repo_name: neuropil/edX

max_issues_repo_licenses: Xnet Linux-OpenIB X11

max_forks_repo_name: neuropil/edX

max_forks_repo_licenses: Xnet Linux-OpenIB X11


text:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
    Software: Dictionary
    Tutorial: <http://excript.com/python/funcoes-dicionarios.html>
    Data: 11/06/2018
    Athor: RodriguesFAS
    Email: franciscosouzaacer@gmail.com
"""

import re
import sys
import nltk
import numpy as np
import pandas as pd

reload(sys)
sys.setdefaultencoding('utf-8')

path_root = '/home/rodriguesfas/Workspace/My-K-NN/data/out/'
path_dataset_input = path_root + 'generated-polarity-data.csv'
path_stop_list = path_root + '../stopwords/stopwords.txt'

"""
    Debug Console
    Flag
        True
        False
"""
TEST = True

def LOG(text):
    if TEST is True:
        print(text)

def remove_stopword_nltk(dataset):
    cachedStopWords = stopwords.words("english")
    dataset = ' '.join(
        [word for word in dataset.lower().split() if word not in cachedStopWords])
    return dataset.strip().strip()

def remove_stopword_list(dataset):
    stop_list = open(path_stop_list).read()
    words_filtered = dataset[:]
    words_filtered = [i for i in dataset.split() if not i in stop_list]
    return (" ".join(words_filtered)).strip()

def stemmer(dataset):
    stemmer = nltk.stem.RSLPStemmer()
    words = []
    for word in dataset.split():
        words.append(stemmer.stem(word))
    return (" ".join(words)).strip()

def remove_very_small_words(dataset):
    dataset = re.sub(r'\b\w{1,3}\b', '', dataset)
    return dataset.strip()

def load_dataset(path_dataset):
    LOG('Loading data..')
    with open(path_dataset) as documents:
        data = []
        index = 0
        for document in documents:
            temp = [document.split(",")[0], document.split(",")[1].strip()]
            data.append(temp)
            index += 1
        print data

def main():
    load_dataset(path_dataset_input)

if __name__ == '__main__':
    main()

max_stars_repo_name: MWTA/My-K-NN

max_issues_repo_name: MWTA/My-K-NN

max_forks_repo_name: MWTA/My-K-NN


text:
"""Authors: Luiz Tauffer, Cody Baker, and Ben Dichter."""
import collections.abc
import inspect

import numpy as np

def dict_deep_update(d: dict, u: dict, append_list: bool = True, remove_repeats: bool = True) -> dict:
    """Perform an update to all nested keys of dictionary d from dictionary u."""
    for k, v in u.items():
        if isinstance(v, collections.abc.Mapping):
            d[k] = dict_deep_update(d.get(k, {}), v,
                                    append_list=append_list,
                                    remove_repeats=remove_repeats)
        elif append_list and isinstance(v, list):
            d[k] = d.get(k, []) + v
            # Remove repeated items if they exist
            if remove_repeats and len(v) > 0 and not isinstance(v[0], dict):
                d[k] = list(set(d[k]))
        else:
            d[k] = v
    return d

def get_base_schema(tag=None, root=False, id_=None, **kwargs) -> dict:
    """Return the base schema used for all other schemas."""
    base_schema = dict(
        required=[],
        properties={},
        type='object',
        additionalProperties=False
    )
    if tag is not None:
        base_schema.update(tag=tag)
    if root:
        base_schema.update({
            "$schema": "http://json-schema.org/draft-07/schema#"
        })
    if id_:
        base_schema.update({"$id": id_})
    base_schema.update(**kwargs)
    return base_schema

def get_schema_from_method_signature(class_method: classmethod, exclude: list = None) -> dict:
    """
    Take a class method and return a json-schema of the input args.

    Parameters
    ----------
    class_method: function
    exclude: list, optional
    Returns
    -------
    dict
    """
    if exclude is None:
        exclude = ['self', 'kwargs']
    else:
        exclude = exclude + ['self', 'kwargs']
    input_schema = get_base_schema()
    annotation_json_type_map = {
        bool: "boolean",
        str: "string",
        int: "number",
        float: "number",
        dict: "object",
        list: "array"
    }

    for param_name, param in inspect.signature(class_method).parameters.items():
        if param_name not in exclude:
            if param.annotation:
                if hasattr(param.annotation, "__args__"):
                    args = param.annotation.__args__
                    valid_args = [x in annotation_json_type_map for x in args]
                    if any(valid_args):
                        param_types = [annotation_json_type_map[x] for x in np.array(args)[valid_args]]
                    else:
                        raise ValueError("No valid arguments were found in the json type mapping!")
                    if len(set(param_types)) > 1:
                        raise ValueError("Conflicting json parameter types were detected from the annotation! "
                                         f"{param.annotation.__args__} found.")
                    param_type = param_types[0]
                else:
                    arg = param.annotation
                    if arg in annotation_json_type_map:
                        param_type = annotation_json_type_map[arg]
                    else:
                        raise ValueError("No valid arguments were found in the json type mapping!")
            else:
                raise NotImplementedError(f"The annotation type of '{param}' in function '{class_method}' "
                                          "is not implemented! Please request it to be added at github.com/"
                                          "catalystneuro/nwb-conversion-tools/issues or create the json-schema"
                                          "for this method manually.")
            arg_spec = {
                param_name: dict(
                    type=param_type
                )
            }
            if param.default is param.empty:
                input_schema['required'].append(param_name)
            elif param.default is not None:
                arg_spec[param_name].update(default=param.default)
            input_schema['properties'].update(arg_spec)
        input_schema['additionalProperties'] = param.kind == inspect.Parameter.VAR_KEYWORD
    return input_schema

def fill_defaults(schema: dict, defaults: dict, overwrite: bool = True):
    """
    Insert the values of the defaults dict as default values in the schema in place.

    Parameters
    ----------
    schema: dict
    defaults: dict
    overwrite: bool
    """
    for key, val in schema['properties'].items():
        if key in defaults:
            if val['type'] == 'object':
                fill_defaults(val, defaults[key], overwrite=overwrite)
            else:
                if overwrite or ('default' not in val):
                    val['default'] = defaults[key]

def unroot_schema(schema: dict):
    """
    Modify a json-schema dictionary to make it not root.

    Parameters
    ----------
    schema: dict
    """
    terms = ('required', 'properties', 'type', 'additionalProperties',
             'title', 'description')
    return {k: v for k, v in schema.items() if k in terms}

max_stars_repo_name: sneakers-the-rat/nwb-conversion-tools

max_issues_repo_name: sneakers-the-rat/nwb-conversion-tools

max_forks_repo_name: sneakers-the-rat/nwb-conversion-tools