Instruction:
Can you generate the documentation for the following Python 3 function
def copy_texture_memory_args(self, texmem_args):

        filter_mode_map = { 'point': drv.filter_mode.POINT,
                            'linear': drv.filter_mode.LINEAR }
        address_mode_map = { 'border': drv.address_mode.BORDER,
                             'clamp': drv.address_mode.CLAMP,
                             'mirror': drv.address_mode.MIRROR,
                             'wrap': drv.address_mode.WRAP }

        logging.debug('copy_texture_memory_args called')
        logging.debug('current module: ' + str(self.current_module))
        self.texrefs = []
        for k, v in texmem_args.items():
            tex = self.current_module.get_texref(k)
            self.texrefs.append(tex)

            logging.debug('copying to texture: ' + str(k))
            if not isinstance(v, dict):
                data = v
            else:
                data = v['array']
            logging.debug('texture to be copied: ')
            logging.debug(data.nbytes)
            logging.debug(data.dtype)
            logging.debug(data.flags)

            drv.matrix_to_texref(data, tex, order="C")

            if isinstance(v, dict):
                if 'address_mode' in v and v['address_mode'] is not None:
                    # address_mode is set per axis
                    amode = v['address_mode']
                    if not isinstance(amode, list):
                        amode = [ amode ] * data.ndim
                    for i, m in enumerate(amode):
                        try:
                            if m is not None:
                                tex.set_address_mode(i, address_mode_map[m])
                        except KeyError:
                            raise ValueError('Unknown address mode: ' + m)
                if 'filter_mode' in v and v['filter_mode'] is not None:
                    fmode = v['filter_mode']
                    try:
                        tex.set_filter_mode(filter_mode_map[fmode])
                    except KeyError:
                        raise ValueError('Unknown filter mode: ' + fmode)
                if 'normalized_coordinates' in v and v['normalized_coordinates']:
                    tex.set_flags(tex.get_flags() | drv.TRSF_NORMALIZED_COORDINATES)

Response: adds texture memory arguments to the most recently compiled module


Instruction:
How would you explain what the following Python 3 function does
def run_kernel(self, func, gpu_args, threads, grid):
        func(*gpu_args, block=threads, grid=grid, texrefs=self.texrefs)

Response: runs the CUDA kernel passed as func


Instruction:
Create a Python 3 function for
setting the memory in allocation to the value in value

Response:
def memset(self, allocation, value, size):
        """set the memory in allocation to the value in value

        :param allocation: A GPU memory allocation unit
        :type allocation: pycuda.driver.DeviceAllocation

        :param value: The value to set the memory to
        :type value: a single 8-bit unsigned int

        :param size: The size of to the allocation unit in bytes
        :type size: int

        """
        drv.memset_d8(allocation, value, size)


Instruction:
How would you explain what the following Python 3 function does
def memcpy_dtoh(self, dest, src):
        if isinstance(src, drv.DeviceAllocation):
            drv.memcpy_dtoh(dest, src)
        else:
            dest = src

Response: perform a device to host memory copy


Instruction:
Can you generate the documentation for the following Python 3 function
def memcpy_htod(self, dest, src):
        if isinstance(dest, drv.DeviceAllocation):
            drv.memcpy_htod(dest, src)
        else:
            dest = src

Response: perform a host to device memory copy


Instruction:
How would you implement a function in Python 3 that
tunes the kernel configuration in the parameter space.

Response:
def tune(runner, kernel_options, device_options, tuning_options):
    """ Find the best performing kernel configuration in the parameter space

    :params runner: A runner from kernel_tuner.runners
    :type runner: kernel_tuner.runner

    :param kernel_options: A dictionary with all options for the kernel.
    :type kernel_options: dict

    :param device_options: A dictionary with all options for the device
        on which the kernel should be tuned.
    :type device_options: dict

    :param tuning_options: A dictionary with all options regarding the tuning
        process.
    :type tuning_options: dict

    :returns: A list of dictionaries for executed kernel configurations and their
        execution times. And a dictionary that contains a information
        about the hardware/software environment on which the tuning took place.
    :rtype: list(dict()), dict()

    """

    results = []
    cache = {}

    # SA works with real parameter values and does not need scaling
    tuning_options["scaling"] = False
    args = (kernel_options, tuning_options, runner, results, cache)
    tune_params = tuning_options.tune_params

    # optimization parameters
    T = 1.0
    T_min = 0.001
    alpha = 0.9
    niter = 20

    # generate random starting point and evaluate cost
    pos = []
    for i, _ in enumerate(tune_params.keys()):
        pos.append(random_val(i, tune_params))
    old_cost = _cost_func(pos, *args)

    if tuning_options.verbose:
        c = 0
    # main optimization loop
    while T > T_min:
        if tuning_options.verbose:
            print("iteration: ", c, "T", T, "cost: ", old_cost)
            c += 1

        for i in range(niter):

            new_pos = neighbor(pos, tune_params)
            new_cost = _cost_func(new_pos, *args)

            ap = acceptance_prob(old_cost, new_cost, T)
            r = random.random()

            if ap > r:
                if tuning_options.verbose:
                    print("new position accepted", new_pos, new_cost, 'old:', pos, old_cost, 'ap', ap, 'r', r, 'T', T)
                pos = new_pos
                old_cost = new_cost

        T = T * alpha

    return results, runner.dev.get_environment()


Instruction:
Create a Python 3 function for
calculating acceptance probability of a new resource based on old cost and new cost

Response:
def acceptance_prob(old_cost, new_cost, T):
    """annealing equation, with modifications to work towards a lower value"""
    #if start pos is not valid, always move
    if old_cost == 1e20:
        return 1.0
    #if we have found a valid ps before, never move to nonvalid pos
    if new_cost == 1e20:
        return 0.0
    #always move if new cost is better
    if new_cost < old_cost:
        return 1.0
    #maybe move if old cost is better than new cost depending on T and random value
    return np.exp(((old_cost-new_cost)/old_cost)/T)


Instruction:
How would you code a function in Python 3 to
return a random neighbor of pos

Response:
def neighbor(pos, tune_params):
    """return a random neighbor of pos"""
    size = len(pos)
    pos_out = []
    # random mutation
    # expected value is set that values all dimensions attempt to get mutated
    for i in range(size):
        key = list(tune_params.keys())[i]
        values = tune_params[key]

        if random.random() < 0.2:  #replace with random value
            new_value = random_val(i, tune_params)
        else: #adjacent value
            ind = values.index(pos[i])
            if random.random() > 0.5:
                ind += 1
            else:
                ind -= 1
            ind = min(max(ind, 0), len(values)-1)
            new_value = values[ind]

        pos_out.append(new_value)
    return pos_out


Instruction:
Here you have a function in Python 3, explain what it does
def tune(runner, kernel_options, device_options, tuning_options):

    tune_params = tuning_options.tune_params
    restrictions = tuning_options.restrictions
    verbose = tuning_options.verbose

    #compute cartesian product of all tunable parameters
    parameter_space = itertools.product(*tune_params.values())

    #check for search space restrictions
    if restrictions is not None:
        parameter_space = filter(lambda p: util.check_restrictions(restrictions, p, tune_params.keys(), verbose), parameter_space)

    results, env = runner.run(parameter_space, kernel_options, tuning_options)

    return results, env

Response: Tune all instances in the parameter space


Instruction:
How would you implement a function in Python 3 that
generates a wrapper to call C++ functions from Python This function allows Kernel Tuner to call templated C++ functions that use primitive data types (double, float, int, ...). There is support to convert function arguments from plain pointers to array references. If this is needed, there should be a True value in convert_to_array in the location corresponding to the location in the args array. For example, a Numpy array argument of type float64 and length 10 will be cast using: ``*reinterpret_cast<double(*)[10]>(arg)`` which allows it to be used to call a C++ that is defined as: ``template<typename T, int s>void my_function(T (&arg)[s], ...)`` Arrays of size 1 will be converted to simple non-array references. False indicates that no conversion is performed. Conversion is only support for numpy array arguments. If convert_to_array is passed it should have the same length as the args array. :param function_name: A string containing the name of the C++ function to be wrapped :type function_name: string :param kernel_source: One of the sources for the kernel, could be a function that generates the kernel code, a string containing a filename that points to the kernel source, or just a string that contains the code. :type kernel_source: string or callable :param args: A list of kernel arguments, use numpy arrays for arrays, use numpy.int32 or numpy.float32 for scalars. :type args: list :param convert_to_array: A list of same length as args, containing True or False values indicating whether the corresponding argument in args should be cast to a reference to an array or not. :type convert_to_array: list (True or False) :returns: A string containing the orignal code extended with the wrapper function. The wrapper has "extern C" binding and can be passed to other Kernel Tuner functions, for example run_kernel with lang="C". The name of the wrapper function will be the name of the function with a "_wrapper" postfix. :rtype: string

Response:
def cpp(function_name, kernel_source, args, convert_to_array=None):
    """ Generate a wrapper to call C++ functions from Python

    This function allows Kernel Tuner to call templated C++ functions
    that use primitive data types (double, float, int, ...).

    There is support to convert function arguments from plain pointers
    to array references. If this is needed, there should be a True value
    in convert_to_array in the location corresponding to the location in
    the args array.

    For example, a Numpy array argument of type float64 and length 10
    will be cast using:
    ``*reinterpret_cast<double(*)[10]>(arg)``
    which allows it to be used to call a C++ that is defined as:
    ``template<typename T, int s>void my_function(T (&arg)[s], ...)``

    Arrays of size 1 will be converted to simple non-array references.
    False indicates that no conversion is performed. Conversion
    is only support for numpy array arguments. If convert_to_array is
    passed it should have the same length as the args array.

    :param function_name: A string containing the name of the C++ function
        to be wrapped
    :type function_name: string

    :param kernel_source: One of the sources for the kernel, could be a
        function that generates the kernel code, a string containing a filename
        that points to the kernel source, or just a string that contains the code.
    :type kernel_source: string or callable

    :param args: A list of kernel arguments, use numpy arrays for
        arrays, use numpy.int32 or numpy.float32 for scalars.
    :type args: list

    :param convert_to_array: A list of same length as args, containing
        True or False values indicating whether the corresponding argument
        in args should be cast to a reference to an array or not.
    :type convert_to_array: list (True or False)

    :returns: A string containing the orignal code extended with the wrapper
        function. The wrapper has "extern C" binding and can be passed to
        other Kernel Tuner functions, for example run_kernel with lang="C".
        The name of the wrapper function will be the name of the function with
        a "_wrapper" postfix.
    :rtype: string

    """

    if convert_to_array and len(args) != len(convert_to_array):
        raise ValueError("convert_to_array length should be same as args")

    type_map = {"int8": "char",
                "int16": "short",
                "int32": "int",
                "float32": "float",
                "float64": "double"}

    def type_str(arg):
        if not str(arg.dtype) in type_map:
            raise Value("only primitive data types are supported by the C++ wrapper")
        typestring = type_map[str(arg.dtype)]
        if isinstance(arg, np.ndarray):
            typestring += " *"
        return typestring + " "

    signature = ",".join([type_str(arg) + "arg" + str(i) for i, arg in enumerate(args)])

    if not convert_to_array:
        call_args = ",".join(["arg" + str(i) for i in range(len(args))])
    else:
        call_args = []
        for i, arg in enumerate(args):
            if convert_to_array[i]:
                if not isinstance(arg, np.ndarray):
                    ValueError("conversion to array reference only supported for arguments that are numpy arrays, use length-1 numpy array to pass a scalar by reference")
                if np.prod(arg.shape) > 1:
                    #convert pointer to a reference to an array
                    arg_shape = "".join("[%d]" % i for i in arg.shape)
                    arg_str = "*reinterpret_cast<" + type_map[str(arg.dtype)] + "(*)" + arg_shape + ">(arg" + str(i) + ")"
                else:
                    #a reference is accepted rather than a pointer, just dereference
                    arg_str = "*arg" + str(i)
                call_args.append(arg_str)
                #call_args = ",".join(["*reinterpret_cast<double(*)[9]>(arg" + str(i) + ")" for i in range(len(args))])
            else:
                call_args.append("arg" + str(i))
        call_args_str = ",".join(call_args)

    kernel_string = util.get_kernel_string(kernel_source)

    return """

    %s

    extern "C"
    float %s_wrapper(%s) {

        %s(%s);

        return 0.0f;
    }""" % (kernel_string, function_name, signature, function_name, call_args_str)


Instruction:
Explain what the following Python 3 code does
def ready_argument_list(self, arguments):
        ctype_args = [ None for _ in arguments]

        for i, arg in enumerate(arguments):
            if not isinstance(arg, (numpy.ndarray, numpy.number)):
                raise TypeError("Argument is not numpy ndarray or numpy scalar %s" % type(arg))
            dtype_str = str(arg.dtype)
            data = arg.copy()
            if isinstance(arg, numpy.ndarray):
                if dtype_str in dtype_map.keys():
                    # In numpy <= 1.15, ndarray.ctypes.data_as does not itself keep a reference
                    # to its underlying array, so we need to store a reference to arg.copy()
                    # in the Argument object manually to avoid it being deleted.
                    # (This changed in numpy > 1.15.)
                    data_ctypes = data.ctypes.data_as(C.POINTER(dtype_map[dtype_str]))
                else:
                    raise TypeError("unknown dtype for ndarray")
            elif isinstance(arg, numpy.generic):
                data_ctypes = dtype_map[dtype_str](arg)
            ctype_args[i] = Argument(numpy=data, ctypes=data_ctypes)
        return ctype_args

Response: This method is used to create a list of arguments that can be passed to the C function.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def compile(self, kernel_name, kernel_string):
        logging.debug('compiling ' + kernel_name)

        if self.lib != None:
            self.cleanup_lib()

        compiler_options = ["-fPIC"]

        #detect openmp
        if "#include <omp.h>" in kernel_string or "use omp_lib" in kernel_string:
            logging.debug('set using_openmp to true')
            self.using_openmp = True
            if self.compiler == "pgfortran":
                compiler_options.append("-mp")
            else:
                compiler_options.append("-fopenmp")

        #select right suffix based on compiler
        suffix = ".cc"

        #detect whether to use nvcc as default instead of g++, may overrule an explicitly passed g++
        if ("#include <cuda" in kernel_string) or ("cudaMemcpy" in kernel_string):
            if self.compiler == "g++" and self.nvcc_available:
                self.compiler = "nvcc"

        #if contains device code suffix .cu is required by nvcc
        if self.compiler == "nvcc" and "__global__" in kernel_string:
            suffix = ".cu"
        if self.compiler in ["gfortran", "pgfortran", "ftn", "ifort"]:
            suffix = ".F90"

        if self.compiler == "nvcc":
            compiler_options = ["-Xcompiler=" + c for c in compiler_options]

        if ".c" in suffix:
            if not "extern \"C\"" in kernel_string:
                kernel_string = "extern \"C\" {\n" + kernel_string + "\n}"

        #copy user specified compiler options to current list
        if self.compiler_options:
            compiler_options += self.compiler_options

        lib_args = []
        if "CL/cl.h" in kernel_string:
            lib_args = ["-lOpenCL"]

        logging.debug('using compiler ' + self.compiler)
        logging.debug('compiler_options ' + " ".join(compiler_options))
        logging.debug('lib_args ' + " ".join(lib_args))

        source_file = get_temp_filename(suffix=suffix)
        filename = ".".join(source_file.split(".")[:-1])

        #detect Fortran modules
        match = re.search(r"\s*module\s+([a-zA-Z_]*)", kernel_string)
        if match:
            if self.compiler == "gfortran":
                kernel_name = "__" + match.group(1) + "_MOD_" + kernel_name
            elif self.compiler in ["ftn", "ifort"]:
                kernel_name = match.group(1) + "_mp_" + kernel_name + "_"
            elif self.compiler == "pgfortran":
                kernel_name = match.group(1) + "_" + kernel_name + "_"

        try:
            write_file(source_file, kernel_string)

            lib_extension = ".so"
            if platform.system() == "Darwin":
                lib_extension = ".dylib"

            subprocess.check_call([self.compiler, "-c", source_file] + compiler_options + ["-o", filename + ".o"])
            subprocess.check_call([self.compiler, filename + ".o"] + compiler_options + ["-shared", "-o", filename + lib_extension] + lib_args)

            self.lib = numpy.ctypeslib.load_library(filename, '.')
            func = getattr(self.lib, kernel_name)
            func.restype = C.c_float

        finally:
            delete_temp_file(source_file)
            delete_temp_file(filename+".o")
            delete_temp_file(filename+".so")
            delete_temp_file(filename+".dylib")

        return func

Response: compiles the kernel and returns the function that can be called directly.


Instruction:
Can you tell what is the following Python 3 function doing
def benchmark(self, func, c_args, threads, grid, times):
        time = []
        for _ in range(self.iterations):
            value = self.run_kernel(func, c_args, threads, grid)

            #I would like to replace the following with actually capturing
            #stderr and detecting the error directly in Python, it proved
            #however that capturing stderr for non-Python functions from Python
            #is a rather difficult thing to do
            #
            #The current, less than ideal, scheme uses the convention that a
            #negative time indicates a 'too many resources requested for launch'
            if value < 0.0:
                raise Exception("too many resources requested for launch")

            time.append(value)
        time = sorted(time)
        if times:
            return time
        else:
            if self.iterations > 4:
                return numpy.mean(time[1:-1])
            else:
                return numpy.mean(time)

Response: Benchmarks the kernel for the specific CUDA configuration and returns the average of the CUDA configuration values.


Instruction:
Write a Python 3 script for
running the kernel once returns whatever the kernel returns

Response:
def run_kernel(self, func, c_args, threads, grid):
        """runs the kernel once, returns whatever the kernel returns

        :param func: A C function compiled for this specific configuration
        :type func: ctypes._FuncPtr

        :param c_args: A list of arguments to the function, order should match the
            order in the code. The list should be prepared using
            ready_argument_list().
        :type c_args: list(Argument)

        :param threads: Ignored, but left as argument for now to have the same
            interface as CudaFunctions and OpenCLFunctions.
        :type threads: any

        :param grid: Ignored, but left as argument for now to have the same
            interface as CudaFunctions and OpenCLFunctions.
        :type grid: any

        :returns: A robust average of values returned by the C function.
        :rtype: float
        """
        logging.debug("run_kernel")
        logging.debug("arguments=" + str([str(arg.ctypes) for arg in c_args]))

        time = func(*[arg.ctypes for arg in c_args])

        return time


Instruction:
Write a Python 3 function that can
set the memory in allocation to the value in value in size

Response:
def memset(self, allocation, value, size):
        """set the memory in allocation to the value in value

        :param allocation: An Argument for some memory allocation unit
        :type allocation: Argument

        :param value: The value to set the memory to
        :type value: a single 8-bit unsigned int

        :param size: The size of to the allocation unit in bytes
        :type size: int
        """
        C.memset(allocation.ctypes, value, size)


Instruction:
Write a Python 3 script to
unload the previously loaded shared library.

Response:
def cleanup_lib(self):
        """ unload the previously loaded shared library """
        if not self.using_openmp:
            #this if statement is necessary because shared libraries that use
            #OpenMP will core dump when unloaded, this is a well-known issue with OpenMP
            logging.debug('unloading shared library')
            _ctypes.dlclose(self.lib._handle)


Instruction:
Given the following Python 3 function, write the documentation
def clock(rpc):

    while True:
        yield from rpc.notify('clock', str(datetime.datetime.now()))
        yield from asyncio.sleep(1)

Response:
This task runs forever and notifies all clients subscribed to
    clock once a second.


Instruction:
Here you have a function in Python 3, explain what it does
def decode_msg(raw_msg):

    try:
        msg_data = json.loads(raw_msg)

    except ValueError:
        raise RpcParseError

    # check jsonrpc version
    if 'jsonrpc' not in msg_data or not msg_data['jsonrpc'] == JSONRPC:
        raise RpcInvalidRequestError(msg_id=msg_data.get('id', None))

    # check requierd fields
    if not len(set(['error', 'result', 'method']) & set(msg_data)) == 1:
        raise RpcInvalidRequestError(msg_id=msg_data.get('id', None))

    # find message type
    if 'method' in msg_data:
        if 'id' in msg_data and msg_data['id'] is not None:
            msg_type = JsonRpcMsgTyp.REQUEST

        else:
            msg_type = JsonRpcMsgTyp.NOTIFICATION

    elif 'result' in msg_data:
        msg_type = JsonRpcMsgTyp.RESULT

    elif 'error' in msg_data:
        msg_type = JsonRpcMsgTyp.ERROR

    # Request Objects
    if msg_type in (JsonRpcMsgTyp.REQUEST, JsonRpcMsgTyp.NOTIFICATION):

        # 'method' fields have to be strings
        if type(msg_data['method']) is not str:
            raise RpcInvalidRequestError

        # set empty 'params' if not set
        if 'params' not in msg_data:
            msg_data['params'] = None

        # set empty 'id' if not set
        if 'id' not in msg_data:
            msg_data['id'] = None

    # Response Objects
    if msg_type in (JsonRpcMsgTyp.RESULT, JsonRpcMsgTyp.ERROR):

        # every Response object has to define an id
        if 'id' not in msg_data:
            raise RpcInvalidRequestError(msg_id=msg_data.get('id', None))

    # Error objects
    if msg_type == JsonRpcMsgTyp.ERROR:

        # the error field has to be a dict
        if type(msg_data['error']) is not dict:
            raise RpcInvalidRequestError(msg_id=msg_data.get('id', None))

        # the error field has to define 'code' and 'message'
        if not len(set(['code', 'message']) & set(msg_data['error'])) == 2:
            raise RpcInvalidRequestError(msg_id=msg_data.get('id', None))

        # the error code has to be in the specified ranges
        if not msg_data['error']['code'] in RpcError.lookup_table.keys():
            raise RpcInvalidRequestError(msg_id=msg_data.get('id', None))

        # set empty 'data' field if not set
        if 'data' not in msg_data['error']:
            msg_data['error']['data'] = None

    return JsonRpcMsg(msg_type, msg_data)

Response: Decodes a jsonrpc 2. 0 raw message into JsonRpcMsg objects.


Instruction:
Write a Python 3 script to
switch the schema of the task before it has been run.

Response:
def switch_schema(task, kwargs, **kw):
    """ Switches schema of the task, before it has been run. """
    # Lazily load needed functions, as they import django model functions which
    # in turn load modules that need settings to be loaded and we can't
    # guarantee this module was loaded when the settings were ready.
    from .compat import get_public_schema_name, get_tenant_model

    old_schema = (connection.schema_name, connection.include_public_schema)
    setattr(task, '_old_schema', old_schema)

    schema = (
        get_schema_name_from_task(task, kwargs) or
        get_public_schema_name()
    )

    # If the schema has not changed, don't do anything.
    if connection.schema_name == schema:
        return

    if connection.schema_name != get_public_schema_name():
        connection.set_schema_to_public()

    if schema == get_public_schema_name():
        return

    tenant = get_tenant_model().objects.get(schema_name=schema)
    connection.set_tenant(tenant, include_public=True)


Instruction:
Implement a function in Python 3 to
switch the schema back to the one from before running the task.

Response:
def restore_schema(task, **kwargs):
    """ Switches the schema back to the one from before running the task. """
    from .compat import get_public_schema_name

    schema_name = get_public_schema_name()
    include_public = True

    if hasattr(task, '_old_schema'):
        schema_name, include_public = task._old_schema

    # If the schema names match, don't do anything.
    if connection.schema_name == schema_name:
        return

    connection.set_schema(schema_name, include_public=include_public)


Instruction:
Here you have a function in Python 3, explain what it does
def node_link_data(G, attrs=_attrs):
    id_ = attrs['id']

    data = {}
    data['directed'] = G.is_directed()
    data['graph'] = G.graph
    data['nodes'] = [dict(chain(G.node[n].items(), [(id_, n)])) for n in G]
    data['links'] = []
    for u, v, timeline in G.interactions_iter():
        for t in timeline['t']:
            for tid in past.builtins.xrange(t[0], t[-1]+1):
                data['links'].append({"source": u, "target": v, "time": tid})

    return data

Response: Return data in node - link format that is suitable for JSON serialization of a DyNetx graph.


Instruction:
Here you have a function in Python 3, explain what it does
def node_link_graph(data, directed=False, attrs=_attrs):

    directed = data.get('directed', directed)
    graph = dn.DynGraph()
    if directed:
        graph = graph.to_directed()

    id_ = attrs['id']
    mapping = []
    graph.graph = data.get('graph', {})
    c = count()
    for d in data['nodes']:
        node = d.get(id_, next(c))
        mapping.append(node)
        nodedata = dict((make_str(k), v) for k, v in d.items() if k != id_)
        graph.add_node(node, **nodedata)
    for d in data['links']:
        graph.add_interaction(d['source'], d["target"], d['time'])

    return graph

Response: Return a DyNetx graph from node - link data format.


Instruction:
Can you tell what is the following Python 3 function doing
def compact_timeslot(sind_list):
    tls = sorted(sind_list)
    conversion = {val: idx for idx, val in enumerate(tls)}
    return conversion

Response: Test method. Compact all snapshots into a single one.


Instruction:
Can you tell what is the following Python 3 function doing
def nodes_iter(self, t=None, data=False):
        if t is not None:
            return iter([n for n in self.degree(t=t).values() if n > 0])
        return iter(self._node)

Response: Return an iterator over the nodes with respect to a given temporal snapshot.


Instruction:
Create a Python 3 function to
return a list of the nodes in the flattened graph at a given snapshot.

Response:
def nodes(self, t=None, data=False):
        """Return a list of the nodes in the graph at a given snapshot.

        Parameters
        ----------
        t : snapshot id (default=None)
            If None the the method returns all the nodes of the flattened graph.
        data : boolean, optional (default=False)
               If False return a list of nodes.  If True return a
               two-tuple of node and node data dictionary

        Returns
        -------
        nlist : list
            A list of nodes.  If data=True a list of two-tuples containing
            (node, node data dictionary).

        Examples
        --------
        >>> G = dn.DynGraph()   # or DiGraph, MultiGraph, MultiDiGraph, etc
        >>> G.add_path([0,1,2], 0)
        >>> G.nodes(t=0)
        [0, 1, 2]
        >>> G.add_edge(1, 4, t=1)
        >>> G.nodes(t=0)
        [0, 1, 2]
        """
        return list(self.nodes_iter(t=t, data=data))


Instruction:
Can you write a function in Python 3 where it
returns an iterator over the interaction present in a given snapshot.

Response:
def interactions_iter(self, nbunch=None, t=None):
        """Return an iterator over the interaction present in a given snapshot.

        Edges are returned as tuples
        in the order (node, neighbor).

        Parameters
        ----------
        nbunch : iterable container, optional (default= all nodes)
            A container of nodes.  The container will be iterated
            through once.
        t : snapshot id (default=None)
            If None the the method returns an iterator over the edges of the flattened graph.

        Returns
        -------
        edge_iter : iterator
            An iterator of (u,v) tuples of interaction.

        See Also
        --------
        interaction : return a list of interaction

        Notes
        -----
        Nodes in nbunch that are not in the graph will be (quietly) ignored.
        For directed graphs this returns the out-interaction.

        Examples
        --------
        >>> G = dn.DynGraph()
        >>> G.add_path([0,1,2], 0)
        >>> G.add_interaction(2,3,1)
        >>> [e for e in G.interactions_iter(t=0)]
        [(0, 1), (1, 2)]
        >>> list(G.interactions_iter())
        [(0, 1), (1, 2), (2, 3)]
        """
        seen = {}  # helper dict to keep track of multiply stored interactions
        if nbunch is None:
            nodes_nbrs = self._adj.items()
        else:
            nodes_nbrs = ((n, self._adj[n]) for n in self.nbunch_iter(nbunch))

        for n, nbrs in nodes_nbrs:
            for nbr in nbrs:
                if t is not None:
                    if nbr not in seen and self.__presence_test(n, nbr, t):
                        yield (n, nbr, {"t": [t]})
                else:
                    if nbr not in seen:
                        yield (n, nbr, self._adj[n][nbr])
                seen[n] = 1
        del seen


Instruction:
Write a Python 3 script for
adding an interaction between nodes u and v at time t and e.

Response:
def add_interaction(self, u, v, t=None, e=None):
        """Add an interaction between u and v at time t vanishing (optional) at time e.

        The nodes u and v will be automatically added if they are
        not already in the graph.

        Parameters
        ----------
        u, v : nodes
            Nodes can be, for example, strings or numbers.
            Nodes must be hashable (and not None) Python objects.
        t : appearance snapshot id, mandatory
        e : vanishing snapshot id, optional (default=None)

        See Also
        --------
        add_edges_from : add a collection of interaction at time t

        Notes
        -----
        Adding an interaction that already exists but with different snapshot id updates the interaction data.

        Examples
        --------
        The following all add the interaction e=(1,2, 0) to graph G:

        >>> G = dn.DynGraph()
        >>> G.add_interaction(1, 2, 0)           # explicit two-node form
        >>> G.add_interaction( [(1,2)], t=0 ) # add interaction from iterable container

        Specify the vanishing of the interaction

        >>>> G.add_interaction(1, 3, t=1, e=10)

        will produce an interaction present in snapshots [0, 9]
        """
        if t is None:
            raise nx.NetworkXError(
                "The t argument must be specified.")

        if u not in self._node:
            self._adj[u] = self.adjlist_inner_dict_factory()
            self._node[u] = {}
        if v not in self._node:
            self._adj[v] = self.adjlist_inner_dict_factory()
            self._node[v] = {}

        if type(t) != list:
            t = [t, t]

        for idt in [t[0]]:
            if self.has_edge(u, v) and not self.edge_removal:
                continue
            else:
                if idt not in self.time_to_edge:
                    self.time_to_edge[idt] = {(u, v, "+"): None}
                else:
                    if (u, v, "+") not in self.time_to_edge[idt]:
                        self.time_to_edge[idt][(u, v, "+")] = None

        if e is not None and self.edge_removal:

            t[1] = e - 1
            if e not in self.time_to_edge:
                self.time_to_edge[e] = {(u, v, "-"): None}
            else:
                self.time_to_edge[e][(u, v, "-")] = None

        # add the interaction
        datadict = self._adj[u].get(v, self.edge_attr_dict_factory())

        if 't' in datadict:
            app = datadict['t']
            max_end = app[-1][1]

            if max_end == app[-1][0] and t[0] == app[-1][0] + 1:

                app[-1] = [app[-1][0], t[1]]
                if app[-1][0] + 1 in self.time_to_edge and (u, v, "+") in self.time_to_edge[app[-1][0] + 1]:
                    del self.time_to_edge[app[-1][0] + 1][(u, v, "+")]

            else:
                if t[0] < app[-1][0]:
                    raise ValueError("The specified interaction extension is broader than "
                                     "the ones already present for the given nodes.")

                if t[0] <= max_end < t[1]:
                    app[-1][1] = t[1]
                    if max_end + 1 in self.time_to_edge:
                        if self.edge_removal:
                            del self.time_to_edge[max_end + 1][(u, v, "-")]
                        del self.time_to_edge[t[0]][(u, v, "+")]

                elif max_end == t[0] - 1:
                    if max_end + 1 in self.time_to_edge and (u, v, "+") in self.time_to_edge[max_end + 1]:
                        del self.time_to_edge[max_end + 1][(u, v, "+")]
                        if self.edge_removal:
                            if max_end + 1 in self.time_to_edge and (u, v, '-') in self.time_to_edge[max_end + 1]:
                                del self.time_to_edge[max_end + 1][(u, v, '-')]
                            if t[1] + 1 in self.time_to_edge:
                                self.time_to_edge[t[1] + 1][(u, v, "-")] = None
                            else:
                                self.time_to_edge[t[1] + 1] = {(u, v, "-"): None}

                    app[-1][1] = t[1]
                else:
                    app.append(t)
        else:
            datadict['t'] = [t]

        if e is not None:
            span = range(t[0], t[1] + 1)
            for idt in span:
                if idt not in self.snapshots:
                    self.snapshots[idt] = 1
                else:
                    self.snapshots[idt] += 1
        else:
            for idt in t:
                if idt is not None:
                    if idt not in self.snapshots:
                        self.snapshots[idt] = 1
                    else:
                        self.snapshots[idt] += 1

        self._adj[u][v] = datadict
        self._adj[v][u] = datadict


Instruction:
Explain what the following Python 3 code does
def add_interactions_from(self, ebunch, t=None, e=None):
        # set up attribute dict
        if t is None:
            raise nx.NetworkXError(
                "The t argument must be a specified.")
        # process ebunch
        for ed in ebunch:
            self.add_interaction(ed[0], ed[1], t, e)

Response: Add all the interaction in ebunch at time t to the graph.


Instruction:
Here you have a function in Python 3, explain what it does
def neighbors(self, n, t=None):
        try:
            if t is None:
                return list(self._adj[n])
            else:
                return [i for i in self._adj[n] if self.__presence_test(n, i, t)]
        except KeyError:
            raise nx.NetworkXError("The node %s is not in the graph." % (n,))

Response: Return a list of the nodes connected to the node n at time t.


Instruction:
Write a Python 3 script for
returning an iterator over all neighbors of node n at time t.

Response:
def neighbors_iter(self, n, t=None):
        """Return an iterator over all neighbors of node n at time t.

        Parameters
        ----------
        n : node
           A node in the graph
        t : snapshot id (default=None)
            If None will be returned an iterator over the neighbors of the node on the flattened graph.

        Examples
        --------
        >>> G = dn.DynGraph()
        >>> G.add_path([0,1,2,3], t=0)
        >>> [n for n in G.neighbors_iter(0, t=0)]
        [1]
        """
        try:
            if t is None:
                return iter(self._adj[n])
            else:
                return iter([i for i in self._adj[n] if self.__presence_test(n, i, t)])
        except KeyError:
            raise nx.NetworkXError("The node %s is not in the graph." % (n,))


Instruction:
Make a summary of the following Python 3 code
def degree(self, nbunch=None, t=None):
        if nbunch in self:  # return a single node
            return next(self.degree_iter(nbunch, t))[1]
        else:  # return a dict
            return dict(self.degree_iter(nbunch, t))

Response: Return the degree of a node or nodes at time t.


Instruction:
Implement a Python 3 function for
returning an iterator over the degree of the nodes in a given timeframe.

Response:
def degree_iter(self, nbunch=None, t=None):
        """Return an iterator for (node, degree) at time t.

        The node degree is the number of edges adjacent to the node in a given timeframe.

        Parameters
        ----------
        nbunch : iterable container, optional (default=all nodes)
            A container of nodes.  The container will be iterated
            through once.

        t : snapshot id (default=None)
            If None will be returned an iterator over the degree of nodes on the flattened graph.

        Returns
        -------
        nd_iter : an iterator
            The iterator returns two-tuples of (node, degree).

        See Also
        --------
        degree

        Examples
        --------
        >>> G = dn.DynGraph()
        >>> G.add_path([0,1,2,3], t=0)
        >>> list(G.degree_iter(0, t=0))
        [(0, 1)]
        >>> list(G.degree_iter([0,1], t=0))
        [(0, 1), (1, 2)]
        """
        if nbunch is None:
            nodes_nbrs = self._adj.items()
        else:
            nodes_nbrs = ((n, self._adj[n]) for n in self.nbunch_iter(nbunch))

        if t is None:
            for n, nbrs in nodes_nbrs:
                deg = len(self._adj[n])
                yield (n, deg)
        else:
            for n, nbrs in nodes_nbrs:
                edges_t = len([v for v in nbrs.keys() if self.__presence_test(n, v, t)])
                if edges_t > 0:
                    yield (n, edges_t)
                else:
                    yield (n, 0)


Instruction:
Can you tell what is the following Python 3 function doing
def size(self, t=None):
        s = sum(self.degree(t=t).values()) / 2
        return int(s)

Response: Return the number of edges at time t.


Instruction:
Can you implement a function in Python 3 that
returns the number of nodes in the t snpashot of a dynamic graph.

Response:
def number_of_nodes(self, t=None):
        """Return the number of nodes in the t snpashot of a dynamic graph.

        Parameters
        ----------
        t : snapshot id (default=None)
               If None return the number of nodes in the flattened graph.

        Returns
        -------
        nnodes : int
            The number of nodes in the graph.

        See Also
        --------
        order  which is identical

        Examples
        --------
        >>> G = dn.DynGraph()   # or DiGraph, MultiGraph, MultiDiGraph, etc
        >>> G.add_path([0,1,2], t=0)
        >>> G.number_of_nodes(0)
        3
        """
        if t is None:
            return len(self._node)
        else:
            nds = sum([1 for n in self.degree(t=t).values() if n > 0])
            return nds


Instruction:
Implement a function in Python 3 to
return True if the graph at time t contains the node n.

Response:
def has_node(self, n, t=None):
        """Return True if the graph, at time t, contains the node n.

        Parameters
        ----------
        n : node
        t : snapshot id (default None)
                If None return the presence of the node in the flattened graph.

        Examples
        --------
        >>> G = dn.DynGraph()   # or DiGraph, MultiGraph, MultiDiGraph, etc
        >>> G.add_path([0,1,2], t=0)
        >>> G.has_node(0, t=0)
        True

        It is more readable and simpler to use

        >>> 0 in G
        True

        """
        if t is None:
            try:
                return n in self._node
            except TypeError:
                return False
        else:
            deg = list(self.degree([n], t).values())
            if len(deg) > 0:
                return deg[0] > 0
            else:
                return False


Instruction:
Can you generate the documentation for the following Python 3 function
def add_star(self, nodes, t=None):
        nlist = list(nodes)
        v = nlist[0]
        interaction = ((v, n) for n in nlist[1:])
        self.add_interactions_from(interaction, t)

Response: Add a star at time t.


Instruction:
Can you create a Python 3 function that
adds a path at time t.

Response:
def add_path(self, nodes, t=None):
        """Add a path at time t.

        Parameters
        ----------
        nodes : iterable container
            A container of nodes.
        t : snapshot id (default=None)

        See Also
        --------
        add_path, add_cycle

        Examples
        --------
        >>> G = dn.DynGraph()
        >>> G.add_path([0,1,2,3], t=0)
        """
        nlist = list(nodes)
        interaction = zip(nlist[:-1], nlist[1:])
        self.add_interactions_from(interaction, t)


Instruction:
How would you explain what the following Python 3 function does
def to_directed(self):
        from .dyndigraph import DynDiGraph
        G = DynDiGraph()
        G.name = self.name
        G.add_nodes_from(self)
        for it in self.interactions_iter():
            for t in it[2]['t']:
                G.add_interaction(it[0], it[1], t=t[0], e=t[1])

        G.graph = deepcopy(self.graph)
        G._node = deepcopy(self._node)
        return G

Response: Return a directed representation of the graph.


Instruction:
Can you generate the documentation for the following Python 3 function
def stream_interactions(self):
        timestamps = sorted(self.time_to_edge.keys())
        for t in timestamps:
            for e in self.time_to_edge[t]:
                yield (e[0], e[1], e[2], t)

Response: Generate a temporal ordered stream of interactions.


Instruction:
Given the following Python 3 function, write the documentation
def time_slice(self, t_from, t_to=None):
        # create new graph and copy subgraph into it
        H = self.__class__()

        if t_to is not None:
            if t_to < t_from:
                raise ValueError("Invalid range: t_to must be grater that t_from")
        else:
            t_to = t_from

        for u, v, ts in self.interactions_iter():
            I = t_to
            F = t_from

            for a, b in ts['t']:
                if I <= a and b <= F:
                    H.add_interaction(u, v, a, b)
                elif a <= I and F <= b:
                    H.add_interaction(u, v, I, F)
                elif a <= I <= b and b <= F:
                    H.add_interaction(u, v, I, b)
                elif I <= a <= F and F <= b:
                    H.add_interaction(u, v, a, F)
        return H

Response: Return a DynGraph object containing nodes and interactions present in the given time slice.


Instruction:
Explain what the following Python 3 code does
def interactions_per_snapshots(self, t=None):
        if t is None:
            return {k: v / 2 for k, v in self.snapshots.items()}
        else:
            try:
                return self.snapshots[t] / 2
            except KeyError:
                return 0

Response: Return the number of interactions within a single snapshot t.


Instruction:
Write a Python 3 script for
returning the inter event time distribution of interactions involving u and v.

Response:
def inter_event_time_distribution(self, u=None, v=None):
        """Return the distribution of inter event time.
        If u and v are None the dynamic graph intere event distribution is returned.
        If u is specified the inter event time distribution of interactions involving u is returned.
        If u and v are specified the inter event time distribution of (u, v) interactions is returned

        Parameters
        ----------

        u : node id
        v : node id

        Returns
        -------

        nd : dictionary
            A dictionary from inter event time to number of occurrences

        """
        dist = {}
        if u is None:
            # global inter event
            first = True
            delta = None
            for ext in self.stream_interactions():
                if first:
                    delta = ext
                    first = False
                    continue
                disp = ext[-1] - delta[-1]
                delta = ext
                if disp in dist:
                    dist[disp] += 1
                else:
                    dist[disp] = 1

        elif u is not None and v is None:
            # node inter event
            delta = (0, 0, 0, 0)
            flag = False
            for ext in self.stream_interactions():
                if ext[0] == u or ext[1] == u:
                    if flag:
                        disp = ext[-1] - delta[-1]
                        delta = ext
                        if disp in dist:
                            dist[disp] += 1
                        else:
                            dist[disp] = 1
                    else:
                        delta = ext
                        flag = True
        else:
            # interaction inter event
            evt = self._adj[u][v]['t']
            delta = []

            for i in evt:
                if i[0] != i[1]:
                    for j in [0, 1]:
                        delta.append(i[j])
                else:
                    delta.append(i[0])

            if len(delta) == 2 and delta[0] == delta[1]:
                return {}

            for i in range(0, len(delta) - 1):
                e = delta[i + 1] - delta[i]
                if e not in dist:
                    dist[e] = 1
                else:
                    dist[e] += 1

        return dist


Instruction:
Implement a function in Python 3 to
return an iterator over the degree of the node in a given timeframe.

Response:
def degree_iter(self, nbunch=None, t=None):
        """Return an iterator for (node, degree) at time t.

            The node degree is the number of edges adjacent to the node in a given timeframe.

            Parameters
            ----------
            nbunch : iterable container, optional (default=all nodes)
                A container of nodes.  The container will be iterated
                through once.

            t : snapshot id (default=None)
                If None will be returned an iterator over the degree of nodes on the flattened graph.

            Returns
            -------
            nd_iter : an iterator
                The iterator returns two-tuples of (node, degree).

            See Also
            --------
            degree

            Examples
            --------
            >>> G = dn.DynDiGraph()
            >>> G.add_interaction(0, 1, t=0)
            >>> list(G.degree_iter(0, t=0))
            [(0, 1)]
            >>> list(G.degree_iter([0,1], t=0))
            [(0, 1), (1, 1)]
            """

        if nbunch is None:
            nodes_nbrs = ((n, succs, self._pred[n]) for n, succs in self._succ.items())
        else:
            nodes_nbrs = ((n, self._succ[n], self._pred[n]) for n in self.nbunch_iter(nbunch))

        if t is None:
            for n, succ, pred in nodes_nbrs:
                yield (n, len(succ) + len(pred))

        else:
            for n, succ, pred in nodes_nbrs:
                edges_succ = len([v for v in succ.keys() if self.__presence_test(n, v, t)])
                edges_pred = len([v for v in pred.keys() if self.__presence_test(v, n, t)])
                yield (n, edges_succ + edges_pred)